Python para Ingeniería Comercial¶
Profesor: Félix Ordóñez
Mail: felix.ordonez@usach.cl
Horario: Martes bloque 2 y 3.
Programa¶
Objetivo
Este curso tiene por objetivo introducir un marco conceptual y práctico de programación en Python, junto con aplicaciones en economía y ciencia de datos. Este lenguaje fue desarrollado en 1989 en base a una programación multipropósito, de fácil legibilidad de código, gratuito y de código abierto. A partir de la última década, especialmente desde que se popularizó la librería pandas, el uso de este lenguaje incrementó ampliamente, donde se ha transversalizado en diferentes disciplinas como Data Science, Economía, Astronomía o Inteligencia Artificial, en contraposición de otros lenguajes enfocados sólo en cómputo numérico o estadístico.
Como Python es de código abierto, el desarrollo de nuevo contenido es constante y a gran velocidad, por ejemplo esto ha generado mecanismos para interactuar con otros lenguajes como R, SQL, C++ o Dynare++, se han creado librerías como Numba que permite mejorar sustancialmente el rendimiento de funciones y loops, o librerías dedicadas al Machine Learning como Keras, algo que sin duda ha impulsado su masificación en el mundo académico, el sector público y privado.
A lo largo del semestre se abordarán métodos básicos de programación, la utilización de librerías científicas, visualización y análisis de datos, junto con aplicaciones estadísticas y económicas. Al final del curso se espera que los estudiantes obtengan un nivel intermedio-avanzado en el manejo de Python.
Requerimientos
No es necesario tener conocimientos previos de programación.
Evaluaciones
Actividades cortas: 30%
Actividades intermedias: 30%
Trabajo en grupo: 40%
Informe 1: 10%
Informe 2: 10%
Presentación: 20%
Contenidos
Introducción a Python:
Introducción a un lenguaje de propósito general.
Configuración de Anaconda y Jupyterlab.
Utilizando Python
Aprendiendo lo básico: instalación de librerías, diferentes types y formatos, como utilizar listas, diccionarios y loops.
Funciones: son un bloque de código que puede (o no) recibir un input y mediante una sentencia reaiza una tarea y/o puede devolver un valor. Acá se aprenderá cómo se utilizan, argumentos de entrada y de salida, funciones anidadas, entre otros.
Clases y objetos: La programación orientada a objetos permite administrar el código mediante métodos y estructuras lógicas. En python se utilizan clases para estructurar el código creando un nuevo tipo de objeto. Analizaremos para qué sirven las clases y cómo se utilizan.
Utilización de datos con pandas: esta librería permite analizar bases de datos estructuradas. Se trabajará con bases relacionales como SQL, series de tiempo y matrices.
Introducción al manejo de texto: Una gran virtud de python es la facilidad con que se puede manejar archivos de texto. Para esto, se aprenderá cómo manejar bases de texto, depuración de datos, stopwords, y creación de word clouds.
Visualización de datos: manejo de Matplotlib y Plotly para crear diferentes tipos de gráficos, tablas y paneles dinámicos.
Optimización de código: uso de numba.
Aplicaciones
Oferta y demanda: solución de sistema de ecuaciones lineales.
OLS: realización de una regresión lineal para una ecuación de Mincer mediante datos de empleo chilenos.
Webscraping.
Modelo AR(1): programación de un modelo autoregresivo, gráficos de autocorrelación, persistencia del modelo.
Modelo de crecimiento de Solow: simulación del modelo de crecimiento, gráficos de resultados y análisis de diferentes paramterizaciones.
Colusión: programación de un modelo de cournot, funciones de demanda, costos y benficios, solución del equilibrio y gráficos.
Modelo de Markov-Switching: introducción al modelo de Hamilton (1989) y aplicación para el PIB de Chile.
Overlapping Generations Model (OLG): solución del estado estacionario de un modelo OLG, gráficos de capital y trabajo según generaciones.
Dynare++ y modelos DSGE: instalación de Dynare++ y utilización mediante jupyter, solución de modelos nuevo keynesianos.
Referencias
Aprende a instalar Anaconda en Windows, Mac o Linux. Acá puedes revisar la documentación de Conda en Windows, Mac o Linux.
Índice de paquetes e instalación.
Para introducirte en Jupyter.
Acá puedes encontrar un completo tutorial de Python.
Revisa las principales librerías que se usarán en el curso: NumPy, Pandas, Numba, Matplotlib, Plotly y SciPy.
Para una amplia programación en economía y finanzas usando Python está QuantEcon.
Proyectos de Python en GitHub.
Historia de Python y su desarrollo.
Stackoverflow tiene un gran foro de consultas y respuestas en materia de programación.
import pandas as pd
asdasd
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-1-4d01f3610a36> in <module>
1 import pandas as pd
----> 2 asdasd
NameError: name 'asdasd' is not defined
Clase 2: About Python¶
¿Qué es Python?¶
Python es un lenguaje de propósito general creado en 1989 por Guido van Rossum.
La primera versión Python 0.9.0. fue lanzada en 1991, la versión Python 2.0 en el 2000. La versión 3.0 fue publicada en el 2008.
Python es gratuito y de código abierto. El desarrollo se encuentra coordinado por Python Software Fundation
Actualmente es uno de los lenguajes más populares.
¿Por qué es tan popular?¶
La popularidad de Python con respecto a otros lenguajes, por ejemplo a Matlab, ha incrementado sostenidamente.
La popularidad de Python viene de la mano con la popularidad de librerías como pandas
Es fácil de ocupar.
Es gratuito.
Gran comunidad, ejm: stackoverflow.
Grandes desarrolladores utilizan python: Google, Facebook, Amazon.
Gran número de librerías: para análisis de datos, inteligencia artificial, gráficos, métodos numéricos, etc.
Eficiente, rápido, limpio, flexible.
Se puede integrar con otros lenguajes como R o Julia.
Algunos ejemplos¶
Manejo de bases¶
import numpy as np
import pandas as pd
df = pd.read_csv("/home/felix/Dropbox/ayudantia1.csv", sep="\t")
df2= df.rename(columns = {'Tasa de desempleo': 'desempleo', 'PIB a precios corrientes': 'PIB' }, inplace = False)
df2[20:30]
| Periodo | desempleo | PIB | |
|---|---|---|---|
| 20 | 01/03/15 | 6.23 | 39179.71 |
| 21 | 01/06/15 | 6.67 | 39535.45 |
| 22 | 01/09/15 | 6.54 | 38263.48 |
| 23 | 01/12/15 | 5.87 | 42574.71 |
| 24 | 01/03/16 | 6.49 | 41953.61 |
| 25 | 01/06/16 | 7.02 | 41447.91 |
| 26 | 01/09/16 | 7.03 | 40805.27 |
| 27 | 01/12/16 | 6.20 | 45330.60 |
| 28 | 01/03/17 | 7.04 | 43602.20 |
| 29 | 01/06/17 | 7.31 | 44040.88 |
Gráficos¶
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(19680801)
mu_x = 200
sigma_x = 25
x = np.random.normal(mu_x, sigma_x, size=100)
mu_w = 200
sigma_w = 10
w = np.random.normal(mu_w, sigma_w, size=100)
fig, axs = plt.subplots(nrows=2, ncols=2)
axs[0, 0].hist(x, 20, density=True, histtype='stepfilled', facecolor='g',
alpha=0.75)
axs[0, 0].set_title('stepfilled')
axs[0, 1].hist(x, 20, density=True, histtype='step', facecolor='g',
alpha=0.75)
axs[0, 1].set_title('step')
axs[1, 0].hist(x, density=True, histtype='barstacked', rwidth=0.8)
axs[1, 0].hist(w, density=True, histtype='barstacked', rwidth=0.8)
axs[1, 0].set_title('barstacked')
# Create a histogram by providing the bin edges (unequally spaced).
bins = [100, 150, 180, 195, 205, 220, 250, 300]
axs[1, 1].hist(x, bins, density=True, histtype='bar', rwidth=0.8)
axs[1, 1].set_title('bar, unequal bins')
fig.tight_layout()
plt.show()
np.random.seed(19680801)
Z = np.random.rand(6, 10)
x = np.arange(-0.5, 10, 1) # len = 11
y = np.arange(4.5, 11, 1) # len = 7
fig, ax = plt.subplots()
ax.pcolormesh(x, y, Z)
<matplotlib.collections.QuadMesh at 0x7f0a2b6d0190>
import matplotlib.pyplot as plt
from matplotlib import cm
from matplotlib.ticker import LinearLocator
import numpy as np
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
# Make data.
X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)
# Plot the surface.
surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
linewidth=0, antialiased=False)
# Customize the z axis.
ax.set_zlim(-1.01, 1.01)
ax.zaxis.set_major_locator(LinearLocator(10))
# A StrMethodFormatter is used automatically
ax.zaxis.set_major_formatter('{x:.02f}')
# Add a color bar which maps values to colors.
fig.colorbar(surf, shrink=0.5, aspect=5)
plt.show()
Regresiones¶
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.api as sm
from statsmodels.sandbox.regression.predstd import wls_prediction_std
np.random.seed(9876789)
nsample = 100
x = np.linspace(0, 10, 100)
X = np.column_stack((x, x**2))
beta = np.array([1, 0.1, 10])
e = np.random.normal(size=nsample)
X = sm.add_constant(X)
y = np.dot(X, beta) + e
model = sm.OLS(y, X)
results = model.fit()
print(results.summary())
nsample = 50
sig = 0.5
x = np.linspace(0, 20, nsample)
X = np.column_stack((x, np.sin(x), (x-5)**2, np.ones(nsample)))
beta = [0.5, 0.5, -0.02, 5.]
y_true = np.dot(X, beta)
y = y_true + sig * np.random.normal(size=nsample)
res = sm.OLS(y, X).fit()
prstd, iv_l, iv_u = wls_prediction_std(res)
fig, ax = plt.subplots(figsize=(8,6))
ax.plot(x, y, 'o', label="data")
ax.plot(x, y_true, 'b-', label="True")
ax.plot(x, res.fittedvalues, 'r--.', label="OLS")
ax.plot(x, iv_u, 'r--')
ax.plot(x, iv_l, 'r--')
ax.legend(loc='best');
OLS Regression Results
==============================================================================
Dep. Variable: y R-squared: 1.000
Model: OLS Adj. R-squared: 1.000
Method: Least Squares F-statistic: 4.020e+06
Date: Mon, 04 Apr 2022 Prob (F-statistic): 2.83e-239
Time: 20:46:32 Log-Likelihood: -146.51
No. Observations: 100 AIC: 299.0
Df Residuals: 97 BIC: 306.8
Df Model: 2
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 1.3423 0.313 4.292 0.000 0.722 1.963
x1 -0.0402 0.145 -0.278 0.781 -0.327 0.247
x2 10.0103 0.014 715.745 0.000 9.982 10.038
==============================================================================
Omnibus: 2.042 Durbin-Watson: 2.274
Prob(Omnibus): 0.360 Jarque-Bera (JB): 1.875
Skew: 0.234 Prob(JB): 0.392
Kurtosis: 2.519 Cond. No. 144.
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
Ejemplos covid simulation¶
Anaconda¶
Anaconda es “una distribución libre y abierta de los lenguajes Python y R”.
Tiene soporte para Windows, Mac o Linux.
Ejemplo de cómo instalar https://www.youtube.com/watch?v=52h3r_lROGY&t=541s
Para Mac¶
Una vez instaldo Anaconda, abrir una terminal.
En la terminal, escribir python.
Si python está correctamente instalado les va a mostrar la versión junto a otra información. Por ejemplo
Tareas¶
Chequear si Python está instalado.
Usar Jupyter para abrir el archivo de intro.ipynb
Instalar
pandasusando conda.Instalar
numpyusando pip.Responder el siguiente formulario: https://forms.gle/hBx1xD5fLBK5NF8QA
Clase 3-4: lo básico¶
Librerías
Funciones (intro)
Variables
Types
Listas
Arrays
Loops
Conceptos básicos clases anteriores:
Qué es python
Anaconda
Jupyter lab
Archivo notebook -> crear un nuevo notebook
Terminal
Ruta donde están nuestros archivos
Cómo instalar una librería usando conda o pip
1. Librerías¶
Antes de definir una librería necesitamos definir un módulo. Corresponde a un archivo con un código de Python.
Entonces, una librería va a ser una colección de módulos. Un paquete va a ser una librería que podemos instalar mediante un package manager.
¿Para qué utilizamos una librería?
Cada librería va a contener una colección de módulos, por ejemplo, funciones que nos van a permitir realizar operaciones matemáticas, graficar, importar datos, etc.
En esta clase vamos a utilizar la librería numpy (la instalamos la clase 2). Esta librería es fundamental para la computación científica, entregando un gran número de operaciones matemáticas.
Si no la tiene instalada aún, se puede hacer mediante el código pip install numpy. La documentación de numpy la encuentra en https://numpy.org/doc/stable/
Algunos ejemplos de qué podemos hacer con esta librería:
#1. Importar librería
import numpy as np
#2. usar librería para crear un vector
x = np.array([1,2,3])
#3. Realizar suma de valores dentro de un vector
np.sum(x)
#4. Valor absoluto
np.abs(x)
#5. Raíz cuadrada
np.sqrt(x)
#6. Transponer
np.transpose(x);
2. Funciones (intro)¶
Una función va a ser un código que almacena una tarea particular y puede ser llamada cuando uno quiera mediante el nombre de la función. Se le puede entregar un input y retorna un oputput.
En esta clase vamos a utilizar algunas funciones básicas como print() o type(). Las funciones se caracterizan por tener ‘nombre’ + ‘(input)’ o ‘nombre’ + ‘()’.
print('hola mundo')
x = 'hola mundo'
print(x)
print(x, type(x))
hola mundo
hola mundo
hola mundo <class 'str'>
3. Variables¶
Corresponden a un elemento que almacena información. Esta información puede tener diferentes typeso características.
En lo que sigue veremos como crear una variable y los difentes tipos.
4. Types¶
Los lenguajes de programación tienen tipos de datos. Cada uno tiene diferentes propiedades y sirve para diferentes acciones.
Python tiene los siguientes tipos de datos:
Texto:
strNúmero:
int,float,comlexSecuencial:
list,tuple,rangeMapping:
dictSet:
set, frozensetBoolean:
boolBinario:
bytes,bytearray,memoryview
Ejemplos¶
x = "Hola mundo"
print(x, type(x))
Hola mundo <class 'str'>
x = 20
print(x, type(x))
20 <class 'int'>
x = 20.5
print(x, type(x))
20.5 <class 'float'>
x = 1j
print(x, type(x))
1j <class 'complex'>
x = ["gatos", "perros", "canarios"]
print(x, type(x))
['gatos', 'perros', 'canarios'] <class 'list'>
x = ("gatos", "perros", "canarios")
print(x, type(x))
('gatos', 'perros', 'canarios') <class 'tuple'>
x = range(5)
print(x, type(x))
range(0, 5) <class 'range'>
x = {"gatos":2, "perros":3}
print(x, type(x))
{'gatos': 2, 'perros': 3} <class 'dict'>
x = True
print(x, type(x))
True <class 'bool'>
Ejercicios:¶
Strings (texto)
Int - Float
Boolean
¿Cómo creamos una variable de texto?
#Para crear un string debe ser entre comillas
x = hola
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-12-48173a3c27f5> in <module>
1 #Para crear un string debe ser entre comillas
----> 2 x = hola
NameError: name 'hola' is not defined
#Se pueden agregar
x = 'hola'
y = "mundo"
z = x + y
print(z)
holamundo
#Se pueden crear de diferentes maneras
x = "hola"
y = "mundo"
z = x + " " + y + "\n" + "un número puede ser string: " + "10 o " + str(10)
print(z)
hola mundo
un número puede ser string: 10 o 10
#Un número puede ser string -> no se pueden hacer operaciones matemáticas
x = "10"
y = "10"
z = x+y
print(z)
1010
Una variable del tipo numérica nos permite realizar operaciones matemáticas
x = 10
y = 20.5
z = x + y
print(z)
30.5
x = (2 * 5 + 10)**2
print(x)
400
¿Se pueden juntar variables de diferentes tipos?
x = '10'
y = 10
z = x + y
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-47-013104e6ffaf> in <module>
1 x = '10'
2 y = 10
----> 3 z = x + y
TypeError: can only concatenate str (not "int") to str
x = '10'
x = int(x)
y = 10
z = x + y
print(z)
20
¿Cómo evalúo si se cumple una condición?
z == 10
False
x = True
y = False
print(x + y)
print(x + x)
print(y + y)
1
2
0
¿Se puede guardar una condición como variable?
x = 10
variable = x != 11
print("variable= ",variable)
variable= True
x = 10
y = x != 11
print(y)
True
Para evaluar un “o” se utiliza “or”, mientras que para un “y” se usa “and”
print(x == 10 or y == False)
print(x == 10 and y == False)
print(x > 10 and y == True)
print(x <= 10 and y == True)
True
False
False
True
5. Listas¶
Una lista va a ser un contenedor de información. Permite diferentes types.
Para crear una lista se pueden usar dos métodos:
Usando “[]”
o usando list()
x = ['a', 1, 1.1, True]
print(x)
['a', 1, 1.1, True]
Otra forma de crear listas:
x = list()
y = [x, x ]
print(y)
[[], []]
¿Se puede acceder a los elementos de una lista?
x = ['a', 1, 1.1, True]
print(x[0])
print(x[1])
print(x[2])
a
1
1.1
Posición en una lista
La posición parte del índice 0.
Si la lista es [a, b, c], la posición de cada elemento será [0, 1, 2].
¿Se pueden hacer operaciones matemáticas con listas?
print(x + x)
['a', 1, 1.1, True, 'a', 1, 1.1, True]
y si son sólo elementos numéricos?
x = [1, 2]
y = [2, 2]
print(x + y)
print(x*x)
[1, 2, 2, 2]
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-36-d32218a19255> in <module>
2 y = [2, 2]
3 print(x + y)
----> 4 print(x*x)
TypeError: can't multiply sequence by non-int of type 'list'
Si podemos realizar operaciones matemáticas sobre los elementos de una lista
print(x[0] + y[1])
3
¿Cómo agregar elementos a una lista?
x = list()
x.append(10)
x.append('hola')
print(x)
[10, 'hola']
Para acceder al total de elementos de una lista usamos la función len()
len(x)
2
Para borrar elementos podemos usar pop() o remove()
x = [10, 'hola']
x.pop(0)
print(x)
['hola']
x = [10, 'hola']
x.remove(10)
print(x)
['hola']
6. Arrays¶
Cuando queremos hacer operaciones matemáticas con vectores o matrices vamos a utilizar arrays.
Para esto usamos numpy: import numpy as np
import numpy as np
x = [1,2,3,4,5]
x_arr = np.array(x)
print("x:", x)
print("x_arr:", x_arr)
x: [1, 2, 3, 4, 5]
x_arr: [1 2 3 4 5]
print(type(x))
print(type(x_arr))
<class 'list'>
<class 'numpy.ndarray'>
La ventaja de usar arrays es que nos permite hacer operaciones matemáticas
x = np.array([0, 1, 2])
print(x + x)
print(x * 2)
print(x*x)
[0 2 4]
[0 2 4]
[0 1 4]
x = [[1, 2], [3, 4]]
x = np.array(x)
print(x)
print("len:", len(x), " x ", len(x[0]))
[[1 2]
[3 4]]
len: 2 x 2
¿Si tenemos un vector y una matriz cómo realizamos una multiplicación?
x = np.array([[2, 2], [2, 2]])
#1. Multiplicación de cada elemento de la matriz
print("Caso 1:\n", x * x)
#2. Multiplicación de matrices
print("Caso 2:\n", x @ x)
Caso 1:
[[4 4]
[4 4]]
Caso 2:
[[8 8]
[8 8]]
7. Loops¶
Vamos a utilizar loops para crear iteraciones sobre una secuencia, un rango determinado, por ejemplo una lista, de 0 a 10, etc.
Para crear una iteración vamos a usar for
for i in range(0, 10):
print(i)
0
1
2
3
4
5
6
7
8
9
x = [0, 1, 'a', True]
for i in range(0, len(x)):
print(i)
0
1
2
3
x = np.array([0, 1, 2, 3])
for i in range(0, len(x)):
print(i)
0
1
2
3
x = [0, 1, 'a', True]
for i in x:
print(i)
0
1
a
True
x = [1, 2, 3]
y = [4, 5 ,6]
for i in range(0, len(x)):
print(x[i] + y[i])
5
7
9
x = [1, 2, 3]
y = [4, 5 ,6]
for i in x:
for j in y:
print((i,j))
(1, 4)
(1, 5)
(1, 6)
(2, 4)
(2, 5)
(2, 6)
(3, 4)
(3, 5)
(3, 6)
Sintaxis va a ser la estructura del código.
#nombre de la variable, signo = , valor
x = 10
#lista: nombre de la lista, signo = , [ valor ]
x = [10, 20]
#Iteración: for, iterador 'i', entre 'in', rango o lista (range(0, 10), [1,2,3]), ':'
for i in range(0, 10):
print(i)
#Una vez me salgo del espacio se acaba la iteración
x = 10
0
1
2
3
4
5
6
7
8
9
x = 10
z = 'b'
a = list()
print(a)
a.append(x)
print(a)
a = [x, z]
print(a)
a.append('b')
print(a)
[]
[10]
[10, 'b']
[10, 'b', 'b']
Actividad en clases¶
¿Cuál es la diferencia entre una librería y una función? de un ejemplo de cada una.
¿Cuál es la diferencia entre un type y una variable? muestre con un ejemplo de código.
¿Cuál es la diferencia entre una lista y un array?
¿Para qué nos sirve un loop?
Crear 5 variables que se llamen “var_” + type: str, float, int, bool, list. Estas variables deben ser del type respectivo.
¿De qué type son las siguientes operaciones?
10*10.5
True*False
True*10
str(10) + str(20.5)
int(str(10)) + float(str(20.5))
int(10.5)
[1, 10., “a”]
Crear un array de 2x2 que tenga los elementos (1,2,3,4) y mostrar cómo se puede acceder al elemento 4.
evalúe si [1,2,3] es igual a np.array([1,2,3]). Entregue una intuición.
Utilice
foryprint()para mostrar mediante un loop números de 0 al 10 y luego otro loop para mostrar los elementos del 5 al 10.El siguiente código tiene un error. El objetivo es sumar los iteradores en un loop. Explique el problema que tiene el código y por qué no llega al resultado (45).
for i in range(10):
x = 0
x = x+i
x
9
Clase 5-6: lo básico (continuación)¶
En esta clase veremos:
Loops
Input/output
If
Conceptos claves que revisamos la clase anterior, deberíamos responder qué son, para qué se ocupan, cómo se ocupan:
Librerías
Funciones (intro)
Variables
Types
Listas
Arrays
1. Loops¶
Vamos a utilizar loops para crear iteraciones sobre una secuencia, un rango determinado, por ejemplo una lista, de 0 a 10, etc.
Para crear una iteración vamos a usar for.
La sintaxis es: for + iterador + in + sobre lo que iteramos + :
#Lo más básico es que iteramos sobre un rango
#un rango es un tipo de datos entre ciertos valores
print(range(5))
#Podemos iterar sobre un rango
for i in range(0, 10):
print(i)
range(0, 5)
0
1
2
3
4
5
6
7
8
9
#Podemos iterar sobre una lista: iteramos en el rango de valores que tiene la lista
x = [0, 1, 'a', True]
for i in range(0, len(x)):
print(i)
0
1
2
3
#Podemos iterar sobre un array
import numpy as np
x = np.array([0, 1, 2, 3])
for i in range(0, len(x)):
print(i)
0
1
2
3
#Podemos iterar sobre los elementos de la lista
x = [0, 1, 'a', True]
for i in x:
print(i)
0
1
a
True
#Podemos usar la iteración para acceder a elementos de una lista
x = [1, 2, 3]
y = [4, 5 ,6]
for i in range(0, len(x)):
print(x[i] + y[i])
5
7
9
#Podemos hacer iteraciones anidadas (for dentro de un for)
x = [1, 2, 3]
y = [4, 5 ,6]
for i in x:
for j in y:
print((i,j))
(1, 4)
(1, 5)
(1, 6)
(2, 4)
(2, 5)
(2, 6)
(3, 4)
(3, 5)
(3, 6)
Un aspecto clave es entender dónde existe una variable o lista, y si está dentro o fuera de un loop qué es lo que pasa.
#nombre de la variable, signo = , valor
x = 10
#lista: nombre de la lista, signo = , [ valor ]
x = [10, 20]
#Iteración: for, iterador 'i', entre 'in', rango o lista (range(0, 10), [1,2,3]), ':'
for i in range(0, 10):
print(i)
#Una vez me salgo del espacio se acaba la iteración
x = 10
0
1
2
3
4
5
6
7
8
9
Si creamos una variable antes de la iteración podemos modificarla con cada iteración. Veamos tres ejemplos con x, y, z:
# Creamos x y y fuera de la iteración
x = 0
y = 0
for i in range(1, 5):
z = 0 #creamos z dentro de la iteración
x = x + i
y = i
z = z + i
print("i:", i, ", x=", x, ", y=", y, ", z=", z)
i: 1 , x= 1 , y= 1 , z= 1
i: 2 , x= 3 , y= 2 , z= 2
i: 3 , x= 6 , y= 3 , z= 3
i: 4 , x= 10 , y= 4 , z= 4
Podemos utilizar iteraciones dentro de iteraciones, esto nos puede servir para trabajar con diferentes fuentes de información.
import numpy as np
#linspace(inicio, término, cantidad de elementos)
a = np.linspace(1, 10, 5)
print("type de a:", type(a))
print("a: ", a)
#arange(inicio, término, separador)
b = np.arange(1, 10,2)
print("type de b:", type(b))
print("b: ", b)
type de a: <class 'numpy.ndarray'>
a: [ 1. 3.25 5.5 7.75 10. ]
type de b: <class 'numpy.ndarray'>
b: [1 3 5 7 9]
Vamos a utilizar estas listas para crear un for anidado y guardar un resultado en una lista
#1. Creamos una lista
lista1 = []
#2. Iteramos sobre los valoes de a y b
for i in a:
for j in b:
#3. Anexamos una operación a la lista
# print((i, j), "multiplicacion:", i * j)
lista1.append(i * j)
print(lista1)
[1.0, 3.0, 5.0, 7.0, 9.0, 3.25, 9.75, 16.25, 22.75, 29.25, 5.5, 16.5, 27.5, 38.5, 49.5, 7.75, 23.25, 38.75, 54.25, 69.75, 10.0, 30.0, 50.0, 70.0, 90.0]
#1. Creamos una lista
lista2 = []
#2. Iteramos sobre el largo de las listas a y b
for i in range(0, len(a)):
for j in range(0, len(b)):
#3. Anexamos una operación a la lista
lista2.append(a[i] * b[j])
print(lista2)
#Podemos sumar los valores de una lista con sum()
print("suma de la lista:", sum(lista2))
[1.0, 3.0, 5.0, 7.0, 9.0, 3.25, 9.75, 16.25, 22.75, 29.25, 5.5, 16.5, 27.5, 38.5, 49.5, 7.75, 23.25, 38.75, 54.25, 69.75, 10.0, 30.0, 50.0, 70.0, 90.0]
suma de la lista: 687.5
Son iguales la lista 1 y lista 2?
lista1 == lista2
True
2. Input/Output¶
La función input() nos va a pedir entregar un valor. Esto es útil cuando necesitamos que el usuario nos reporte algún dato.
input()
---------------------------------------------------------------------------
StdinNotImplementedError Traceback (most recent call last)
<ipython-input-13-9c8b639daf2f> in <module>
----> 1 input()
~/miniconda3/lib/python3.9/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
843 """
844 if not self._allow_stdin:
--> 845 raise StdinNotImplementedError(
846 "raw_input was called, but this frontend does not support input requests."
847 )
StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
Podemos incorporar un texto referente a la información solicitada
input("Indique su edad:")
¿Podemos guardar la información?
edad = input("indique su edad:")
#Es una variable del tipo string
#¿Cómo la pasamos a una variable numérica?
#Con int() o float()
print(edad)
3. If/else¶
La operación if nos permite evaluar si se cumple una condición.
Por ejemplo: Iteramos sobre una lista entre (0, 10), si el valor es mayor que 5 muestra el resultado.
Iteramos sobre una lista entre (0, 10): hacemos un for entre 0 y 10.
si el valor es mayor que 5: condición
muestra el resultado: operación
for i in range(0, 10): #iteración
if i > 5: #condición
print(i) #operación
6
7
8
9
¿Qué tipo de operaciones podemos evaluar? Operaciones lógicas:
Igualdad: ==
Desigualdad: !=
Mayor: >
Mayor que: >=
Menor: <
Menor que: <=
a = 10
if a==10:
x = a
print(x)
10
Para evaluar varias situaciones vamos a usar if, elif y else.
Ejemplo: Vamos a crear una lista A utilizando valores de una segunda lista B con valores entre 0-10. Vamos a iterar sobre los valores de la lista A y realizar las siguientes operaciones
Si el valor está entre 0-3 guardamos ese mismo valor en B
Si el valor es mayor que 3 y menor que 5 lo multiplicamos por 2
Si el valor es igual a 5 pedir ingresar un valor con la función input()
Para todo el resto eleva el número al cuadrado
#1. Creamos las listas
A = np.arange(0, 11, 1)
B = []
#2. Iteramos sobre A
for i in A:
#Creamos la primera condición
if i>=0 and i<= 3:
B.append(i)
#Segunda condición
elif i > 3 and i<5:
B.append(i*2)
#Tercera condición
elif i==5:
B.append(float(input("Agregar un valor")))
B.append(input("input 2:"))
#Para todo el resto
else:
B.append(i**2)
Agregar un valor 10
input 2: 10
print("A:", A)
print("B:", B)
A: [ 0 1 2 3 4 5 6 7 8 9 10]
B: [0, 1, 2, 3, 8, 10.0, '10', 36, 49, 64, 81, 100]
x = input("agrega un valor")
type(x)
agrega un valor 10
str
a = 'texto2'
if a != 'texto':
print("ok")
ok
a = [0, 'x', 3]
for i in range(0, len(a)):
print(a[i])
if i == 0:
print("ok")
elif i == 1:
print("ok2")
0
ok
x
ok2
3
Actividad¶
Instrucciones:
Cada pregunta la debe responder en una celda diferente (en total 15 celdas de código).
Antes de cada celda de código debe ir un
markdownque muestre la pregunta que está respondiendo.En la celda de código debe agregar un breve comentario de qué está haciendo.
Acá un ejemplo de cómo va a responder:
Importe una librería
#Importar librería
import numpy as np
Responda las siguientes preguntas.
Crear un libro de jupyter en su carpeta para actividades del curso. Nombre el libro como
Actividad_1Crear una variable de texto, una numérica y otra boolean.
Explique brevemente qué ocurre con la variable x si ejecuto el siguiente código:
x = 10 ,
luego x = x + 10
¿Es lo mismo range(5) y range(0,5)? muestre su resultado mediante una variable boolean.
Crear una lista vacía llamda ‘L1’, luego anexar las tres variables del punto 2. a ‘L1’.
Borrar la variable numérica de L1.
Realice un
forentre el rango 0-10 y realice los siguientes dos ejemplos:Antes del
forcree una variable x = 0, dentro delforsume 1 (x = x + 1)Dentro del
forcree una variable x = 0, luego sume 1 (x = x + 1)¿Cuál es la diferencia?
Genere un array A de dimensiones 2x2 y otro B de dimensiones 2x1. Realice un loop anidado (for dentro de for) para multiplicar cada elemento de A por el de B. Guárdelos en una lista.
Clase 7-8¶
Repaso conceptos clave:
Librería: Colección de modulos. Nos sirve para implementar funciones que permiten tareas específicas como: operaciones matemáticas, gráficos, procesar datos, etc.
Variables: elemento que amacena información de diferentes types.
Types: Tipos de información que podemos utilizar: texto, numérico, secuencial, boolean, etc.
Listas: Contenedor de información. Permite almacenar diferentes types.
Loops: iteraciones que vamos a llamar mediante la palabra for.
Contenidos de la clase:¶
Loops
Input/output
If
Crear funciones
Diccionarios
1. Loops¶
Podemos iterar sobre un rango de valores (a,b). Recordar que la iteración incluye a y no incluye b.
# Iterar sobre un rango de valores
for i in range(5, 10):
print(i)
5
6
7
8
9
Si creamos una variable antes de la iteración podemos modificarla con cada iteración. Veamos tres ejemplos con x, y, z:
# Creamos x y y fuera de la iteración
x = 0
y = 0
for i in range(1, 5):
z = 0 #creamos z dentro de la iteración
x = x + i
y = i
z = z + i
print("i:", i, ", x=", x, ", y=", y, ", z=", z)
i: 1 , x= 1 , y= 1 , z= 1
i: 2 , x= 3 , y= 2 , z= 2
i: 3 , x= 6 , y= 3 , z= 3
i: 4 , x= 10 , y= 4 , z= 4
Podemos utilizar iteraciones dentro de iteraciones, esto nos puede servir para trabajar con diferentes fuentes de información.
La clase pasada vimos como crear una lista manualmente, ahora dos ejemplos para crear una lista numérica (array) entre un rango de valores:
import numpy as np
#linspace(inicio, término, cantidad de elementos)
a = np.linspace(1, 10, 5)
print("type de a:", type(a))
print("a: ", a)
#arange(inicio, término, separador)
b = np.arange(1, 10,2)
print("type de b:", type(b))
print("b: ", b)
type de a: <class 'numpy.ndarray'>
a: [ 1. 3.25 5.5 7.75 10. ]
type de b: <class 'numpy.ndarray'>
b: [1 3 5 7 9]
import numpy as np
inicio = 0
termino = 100
cantidad = 1001
np.linspace(inicio, termino, cantidad)
(termino-inicio)/cantidad
0.0999000999000999
Vamos a utilizar estas listas para crear un for anidado y guardar un resultado en una lista
Recorrer los elementos de la lista
for i in b:
print(i)
1
3
5
7
9
print(a)
print(b)
[ 1. 3.25 5.5 7.75 10. ]
[1 3 5 7 9]
#1. Creamos una lista
lista1 = []
#2. Iteramos sobre los valoes de a y b
for i in a:
for j in b:
#3. Anexamos una operación a la lista
# print((i, j), "multiplicacion:", i * j)
lista1.append(i * j)
print(lista1)
[1.0, 3.0, 5.0, 7.0, 9.0, 3.25, 9.75, 16.25, 22.75, 29.25, 5.5, 16.5, 27.5, 38.5, 49.5, 7.75, 23.25, 38.75, 54.25, 69.75, 10.0, 30.0, 50.0, 70.0, 90.0]
Otra forma de hacer la misma operación
#1. Creamos una lista
lista2 = []
#2. Iteramos sobre el largo de las listas a y b
for i in range(0, len(a)):
for j in range(0, len(b)):
#3. Anexamos una operación a la lista
lista2.append(a[i] * b[j])
print(lista2)
#Podemos sumar los valores de una lista con sum()
print("suma de la lista:", sum(lista2))
[1.0, 3.0, 5.0, 7.0, 9.0, 3.25, 9.75, 16.25, 22.75, 29.25, 5.5, 16.5, 27.5, 38.5, 49.5, 7.75, 23.25, 38.75, 54.25, 69.75, 10.0, 30.0, 50.0, 70.0, 90.0]
suma de la lista: 687.5
Son iguales la lista 1 y lista 2?
lista1 == lista2
True
2. Input/Output¶
La función input() nos va a pedir entregar un valor. Esto es útil cuando necesitamos que el usuario nos reporte algún dato.
input()
---------------------------------------------------------------------------
StdinNotImplementedError Traceback (most recent call last)
<ipython-input-10-9c8b639daf2f> in <module>
----> 1 input()
~/miniconda3/lib/python3.9/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
843 """
844 if not self._allow_stdin:
--> 845 raise StdinNotImplementedError(
846 "raw_input was called, but this frontend does not support input requests."
847 )
StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
Podemos incorporar un texto referente a la información solicitada
input("Indique su edad:")
Indique su edad: 10
'10'
¿Podemos guardar la información?
edad = input("indique su edad:")
#Es una variable del tipo string
#¿Cómo la pasamos a una variable numérica?
#Con int() o float()
indique su edad: 10
print(edad)
10
3. If/else¶
La operación if nos permite evaluar si se cumple una condición.
Por ejemplo: Iteramos sobre una lista entre (0, 10), si el valor es mayor que 5 muestra el resultado.
Iteramos sobre una lista entre (0, 10): hacemos un for entre 0 y 10.
si el valor es mayor que 5: condición
muestra el resultado: operación
for i in range(0, 10): #iteración
if i > 5: #condición
print(i) #operación
6
7
8
9
¿Qué tipo de operaciones podemos evaluar? Operaciones lógicas:
Igualdad: ==
Desigualdad: !=
Mayor: >
Mayor que: >=
Menor: <
Menor que: <=
a = 10
if a==10:
x = a
print(x)
10
Operaciones conjuntas con “or” y “and”
if a == 10 and x >= 5:
print((a, x))
(10, 10)
Para evaluar varias situaciones vamos a usar if, elif y else.
Ejemplo: Vamos a crear una lista A utilizando valores de una segunda lista B con valores entre 0-10. Vamos a iterar sobre los valores de la lista A y realizar las siguientes operaciones
Si el valor está entre 0-3 guardamos ese mismo valor en B
Si el valor es mayor que 3 y menor que 5 lo multiplicamos por 2
Si el valor es igual a 5 pedir ingresar un valor con la función input()
Para todo el resto eleva el número al cuadrado
#1. Creamos las listas
A = np.arange(0, 11, 1)
B = []
#2. Iteramos sobre A
for i in A:
#Creamos la primera condición
if i>=0 and i<= 3:
B.append(i)
#Segunda condición
elif i > 3 and i<5:
B.append(i*2)
#Tercera condición
elif i==5:
B.append(float(input("Agregar un valor")))
B.append(input("input 2:"))
#Para todo el resto
else:
B.append(i**2)
Agregar un valor 10
input 2: 10
print("A:", A)
print("B:", B)
A: [ 0 1 2 3 4 5 6 7 8 9 10]
B: [0, 1, 2, 3, 8, 10.0, '10', 36, 49, 64, 81, 100]
np.zeros(0)
array([], dtype=float64)
x = input("agrega un valor")
type(x)
agrega un valor 1
str
a = 'texto2'
if a != 'texto':
print("ok")
ok
a = [0, 'x', 3]
for i in range(0, len(a)):
print(a[i])
if i == 0:
print("ok")
elif i == 1:
print("ok2")
0
ok
x
ok2
3
4. Crear funciones¶
Una función es un código que nos permite almacenar una una acción. A la función le damos un nombre y luego la podemos invocar utilizando ese nombre.
Un ejemplo de función es print(), mediante su nombre podemos pedir que muestre una variable, un texto u otro.
Ahora vamos a ver cómo se crea una función.
Sintaxis: “def” + “nombre” + “(input)” + “:”
def miprimerafuncion(a): #declaramos la función y establecemos el input
b = a*2 #definimos qué hace la función
return b #Establecemos un output
#definimos el input
a = 10
#llamamos la función
miprimerafuncion(a)
20
podemos evaluar la función con diferentes valores
b = 100
print(miprimerafuncion(b))
print(miprimerafuncion(1000))
200
2000
A una función le podemos dar diferentes input y que entregue variados output
def ejemplo2(a, b):
return a*b, a**b
ejemplo2(10,2)
(20, 100)
podemos guardar los valores del output de la función
X, Y = ejemplo2(10,2)
print("X=", X, "Y=", Y)
X= 20 Y= 100
El input puede ser de diferentes types
def ejemplo3(a):
AA = []
AA.append(a)
return AA
C = ejemplo3("hola")
print(C)
['hola']
print(C)
['hola']
Variable local y global
Una variable local va a existir en un lugar específico. Por ejemplo dentro de la función ejemplo3(a) definimos A=[], esta variable A existe sólo dentro de la función ejemplo3(), es decir es una variable local.
Por otro lado, cuando decimos que A = ejemplo3(“hola”) estamos definiendo una vable global, que existe en todo el espacio del Jupyter, una vez definida puede ser llamada en en cualquier parte.
El ejemplo que utilizamos para probar if/ifelse/else lo podemos guardar en una función que le entremos una lista numérica (A) y que retorne una lista B con las operaciones del if
#1. Creamos la función con un input A
def ejemplo4(A):
#2. Creamos una lista vacía
B = []
#3. Iteramos sobre A
for i in A:
#Creamos la primera condición
if i>=0 and i<= 3:
B.append(i)
#Segunda condición
elif i > 3 and i<5:
B.append(i*2)
#Tercera condición
elif i==5:
B.append(input("Agregar un valor"))
#Todo el resto
else:
B.append(i**2)
#4. Output
return B
#Creamos una lista entre 0-10
A = np.arange(0, 11, 1)
#Llamamos la función y guardamos el resultado en una variable global
B = ejemplo4(A)
Agregar un valor 1
print("A:", A)
print("B:", B)
A: [ 0 1 2 3 4 5 6 7 8 9 10]
B: [0, 1, 2, 3, 8, '1', 36, 49, 64, 81, 100]
5. Diccionarios¶
Un diccionario es una estructura que nos permite almacenar información mediante una llave (key) y un valor. Vamos a llamar tupla a esta llave:valor.
Por ejemplo si tenemos una base como
Podemos crear dos diccionarios, uno para Ana y otro para Félix del tipo:
Ana: {Nombre: Ana, Edad:30, Signo:Libra}
Félix: {Nombre:Félix, Edad:50, Signo:Sagitario}
En este caso las llaves son (Nombre, Edad y Signo).
Para crear un diccionario utilizamos “{}”. La sintaxis es “{” + “llave” + “:” + “valor” + “}”
Ana = {'nombre':'ana', 'edad':30, 'signo':'libra'}
Felix = {'nombre':'felix', 'edad':50, 'signo':'sagitario'}
Para acceder a los elementos del diccionario vamos a usar la llave o el valor
print('La edad de Ana es '+ str(Ana['edad']) + ' y su signo es ' + Ana['signo'])
La edad de Ana es 30 y su signo es libra
Vamos a usar las funciones keys(), values() e items() para ver los valores dentro de un diccionario
#Para ver las llaves
Ana.keys()
dict_keys(['nombre', 'edad', 'signo'])
#Para ver los valores
Felix.values()
dict_values(['felix', 50, 'sagitario'])
#Para ver las tuplas (llave, valor)
Felix.items()
dict_items([('nombre', 'felix'), ('edad', 50), ('signo', 'sagitario')])
Clase 9-10: Funciones, diccionarios y condicionales¶
#Importar librería
import numpy as np
En esta classe vamos a ejercitar respondiendo las siguientes preguntas
Utilice las funciones de numpy
linspace()yarange()para crear dos vectores entre 0-100. El primer vector tiene 1000 elementos entre el rango 0-100 y el segundo se encuentra separado por 1.5 (ejm: 0, 1.5, 3, …).
#Crear vector entre 0-100 con 1000 elementos
vector1 = np.linspace(0, 100, 1000)
print("len(vector1):", len(vector1))
#Crear vector entre 0-100 separados por 1.5
vector2 = np.arange(0, 100, 1.5)
print("len(vector2):", len(vector2))
#Vectores
print("vector1:", vector1[0:10])
print("vector2:", vector2[0:10])
len(vector1): 1000
len(vector2): 67
vector1: [0. 0.1001001 0.2002002 0.3003003 0.4004004 0.5005005 0.6006006
0.7007007 0.8008008 0.9009009]
vector2: [ 0. 1.5 3. 4.5 6. 7.5 9. 10.5 12. 13.5]
Utilizando los vectores de 1. crear un
loop anidadopara calcular la multiplicación entre cada elemento de los vectores. Guarde los resultados en una lista.
#Lista vacía
lista = []
#Loop
for i in vector1:
for j in vector2:
lista.append(i*j)
print("len(lista):", len(lista))
print("len(vector1)*len(vector2):", len(vector1)*len(vector2))
len(lista): 67000
len(vector1)*len(vector2): 67000
Mediante un print() muestre la suma, el promedio, la mediana y la desviación estándar de la lista guardada en 2.
#Suma
print("suma:", np.sum(lista))
#Promedio
print("promedio:", np.mean(lista))
#Mediana
print("mediana:", np.median(lista))
#Desviación estandar
print("Std:", np.std(lista))
suma: 165825000.0
promedio: 2475.0
mediana: 1839.3393393393394
Std: 2202.8088300489767
Utilice la función input() para solicitar la cantidad de mascotas.
#Solicitar input
input("¿Cuántas mascotas tiene?")
---------------------------------------------------------------------------
StdinNotImplementedError Traceback (most recent call last)
<ipython-input-5-1e0ab58c6baf> in <module>
1 #Solicitar input
----> 2 input("¿Cuántas mascotas tiene?")
~/miniconda3/lib/python3.9/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
843 """
844 if not self._allow_stdin:
--> 845 raise StdinNotImplementedError(
846 "raw_input was called, but this frontend does not support input requests."
847 )
StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
Crear una rutina que permita las siguientes operaciones:
Solicitar el número de mascotas (con input()), guardar en una variable.
Si el número de mascotas es cero: imprimir “No tiene mascotas.”
Si el número es entre 1-3: imprimir “Tiene entre 1-3 mascotas.”
Si el número es entre 4-6: imprimir “Tiene entre 4-6 mascotas.”
Si el número es mayor que 6: imprimir “Tiene más de 6 mascotas”.
Si el número es negativo: imprimir “No corresponde”.
*Probar que su rutina cumple bien todas las condiciones. *
mascotas = int(input("¿Cuántas mascotas tiene?"))
if mascotas == 0:
print("No tiene mascotas")
elif mascotas >0 and mascotas <=3 :
print("Tiene entre 1-3 mascotas")
elif mascotas>3 and mascotas <=6:
print("Tiene entre 4-6 mascotas")
elif mascotas>6:
print("Tiene mas de 6 mascotas")
elif mascotas<0:
print("No corresponde")
else:
print("otro caso")
¿Cuántas mascotas tiene? 0
No tiene mascotas
Crear dos listas, una con estilo musical (blues, rock, rap, trap, pop) y otra con grupos (Nina Simone, Led Zeppelin, Makiza, Pablo Chill-e, Dua Lipa). Luego crear una función que tenga como input “estilo” y output “recomendacion”. La función debe permitir:
Leer el input estilo y compararlo con la lista de estilo musical.
Utilizar if/elif/else para crear condiciones que recomiende música. Por ejemplo, si estilo es igual a Blues, recomendar Nina Simone.
Si el estilo no está en la lista de estilo musical, debe mostrar “No tenemos recomendación para su estilo musical”.
El output debe ser la recomendación.
Evaluar si la función se ejecuta correctamente para cada estilo musical
Opción 1
def recomendacion(estilo):
if estilo == "blues":
print("Nina Simone")
elif estilo == "rock":
print("Led Zeppelin")
elif estilo == "rap":
print("Makiza")
elif estilo == "trap":
print("Pablo Chill-e")
elif estilo == "pop":
print("Dua Lipa")
else:
print("No tenemos recomendación para su estilo musical.")
recomendacion('rap')
Makiza
Opción 2
def recomendacion(estilo):
if estilo == "blues":
recomend = "Nina Simone"
elif estilo == "rock":
recomend = "Led Zeppelin"
elif estilo == "rap":
recomend = "Makiza"
elif estilo == "trap":
recomend = "Pablo Chill-e"
elif estilo == "pop":
recomend = "Dua Lipa"
else:
recomend = "No tenemos recomendación para su estilo musical."
return recomend
#Podemos guardar la recomendación en una variable
recomendacion('blues')
'Nina Simone'
Opción 3
estilos = ["blues", "rock", "rap", "trap", "pop"]
grupos = ["Nina Simone", "Led Zeppelin", "Makiza", "Pablo Chill-e", "Dua Lipa"]
def recomendacion(estilo):
for i in range(0, len(estilos)):
if estilo == estilos[i]:
recomend = grupos[i]
break
else:
recomend = "No tenemos recomendación"
return recomend
recomendacion("rock")
'Led Zeppelin'
Crear una función que permita evaluar hasta tres estilos musicales y entregue una lista con las recomendaciones. Por ejemplo, si le entrego una lista con [rock, rap, pop] me debe retornar [Led Zeppelin, Makiza, Dua Lipa]. Adicionalmente:
Si le entrego una lista con 1 o 2 estilos musicales debe entregar 1 o 2 recomendaciones respectivamente.
Si le entrego una lista del tipo [trap, musica clasica] debe retornar la recomendación para trap [Pablo Chill-e].
Si le entrego una lista del tipo [musica clasica] debe retornar un mensaje “no tenemos recomendación para su estilo musical”.
Pasos de la iteración
“blues”: igual a la pregunta 6
[“blues”]:
si el lago del input == 1
iteramos sobre el total de estilos
si input (estilo) en la posición cero (primer elemento) es igual al valor de los estilos (sobre lo que estamos iterando)
entonces guardar el output como el grupo en la posición “i”.
cierre
[“blues”, “rock”]:
si el largo del input es igual a 2
creamos lista vacía para guardar las recomendaciones
iteramos sobre el total de elementos de estilos
Comparamos el primer elemento del input con los estilos ejm: si input[“blues”, rock”], comparamos “blues” con cada elemento de estilos.
Si son iguales, guardamos la recomendación (grupos[i]) en la lista, en caso contrario no hacemos nada.
Repetimos para el segundo elemento del input (“rock”).
[“rock”, “blues”, “pop”]
La lógica es la misma que en 3., sólo que ahora agregamos un tercer elemento y con ello una tercera condición.
estilos = ["blues", "rock", "rap", "trap", "pop"]
grupos = ["Nina Simone", "Led Zeppelin", "Makiza", "Pablo Chill-e", "Dua Lipa"]
def recomendacion(estilo):
#Entrada como texto: ejm "rock"
if type(estilo) == str:
for i in range(0, len(estilos)):
if estilo == estilos[i]:
recomend = grupos[i]
break
else:
recomend = "No tenemos recomendación"
#Entrada como lista ej ["rock"] o ["rock", "blues"]
else:
#1 estilo musical
if len(estilo) == 1:
for i in range(0, len(estilos)):
if estilo[0] == estilos[i]:
recomend = grupos[i]
break
else:
recomend = "No tenemos recomendación"
#2 estilos musicales
elif len(estilo) == 2:
recomend = []
for i in range(0, len(estilos)):
if estilo[0] == estilos[i]:
recomend.append(grupos[i])
elif estilo[1] == estilos[i]:
recomend.append(grupos[i])
#3 estilos musicales:
elif len(estilo) == 3:
recomend = []
for i in range(0, len(estilos)):
if estilo[0] == estilos[i]:
recomend.append(grupos[i])
elif estilo[1] == estilos[i]:
recomend.append(grupos[i])
elif estilo[2] == estilos[i]:
recomend.append(grupos[i])
return recomend
gustos = ["rap", "rock", "blues"]
recomendacion(gustos)
['Nina Simone', 'Led Zeppelin', 'Makiza']
Crear una diccionario a partir de las dos listas donde la llave sea el estilo musical y el valor sea el grupo, ej: {‘rap’:’makiza’…}.
musica_dic = {'blues':'Nina Simone', 'rock':'Led Zeppelin', 'rap':'Makiza', 'trap':'Pablo Chill-e', 'pop':'Dua Lipa' }
print("diccionario:", musica_dic)
print("llaves:", musica_dic.keys())
print("valores:", musica_dic.values())
print("items:", musica_dic.items())
diccionario: {'blues': 'Nina Simone', 'rock': 'Led Zeppelin', 'rap': 'Makiza', 'trap': 'Pablo Chill-e', 'pop': 'Dua Lipa'}
llaves: dict_keys(['blues', 'rock', 'rap', 'trap', 'pop'])
valores: dict_values(['Nina Simone', 'Led Zeppelin', 'Makiza', 'Pablo Chill-e', 'Dua Lipa'])
items: dict_items([('blues', 'Nina Simone'), ('rock', 'Led Zeppelin'), ('rap', 'Makiza'), ('trap', 'Pablo Chill-e'), ('pop', 'Dua Lipa')])
Replicar la función 6. pero ahora utilizando diccionarios donde la función haga lo siguiente:
Evaluar si el input (estilo) está en las
llavesdel diccionario.Si el input está en llave del diccionario recomendar el grupo musical respectivo.
Si no está en la llave del diccionario retornar “No tenemos recomendación para su estilo musical”.
Opción 1
musica_dic = {'blues':'Nina Simone', 'rock':'Led Zeppelin', 'rap':'Makiza', 'trap':'Pablo Chill-e', 'pop':'Dua Lipa' }
def recomendacion(estilo):
for k in musica_dic.keys():
if estilo == k:
recomend = musica_dic[k]
break
else:
recomend = "No tenemos recomendación"
return recomend
recomendacion("pop")
'Dua Lipa'
Opción 2
def recomendacion(estilo):
for k,v in musica_dic.items():
if estilo == k:
recomend = v
break
else:
recomend = "No tenemos recomendación"
return recomend
recomendacion("rap")
'Makiza'
Replicar la función de 7. utilizando diccionarios.
musica_dic = {'blues':'Nina Simone', 'rock':'Led Zeppelin', 'rap':'Makiza', 'trap':'Pablo Chill-e', 'pop':'Dua Lipa' }
def recomendacion(estilo):
#Entrada como texto: ejm "rock"
if type(estilo) == str:
for k, v in musica_dic.items():
if estilo == k:
recomend = v
break
else:
recomend = "No tenemos recomendación"
#Entrada como lista ej ["rock"] o ["rock", "blues"]
else:
#1 estilo musical
recomend = []
if len(estilo) == 1:
for k, v in musica_dic.items():
if estilo[0] == k:
recomend = v
break
else:
recomend = "No tenemos recomendación"
#2 estilos musicales
elif len(estilo) == 2:
recomend = []
for k, v in musica_dic.items():
if estilo[0] == k:
recomend.append(v)
elif estilo[1] == k:
recomend.append(v)
#3 estilos musicales:
elif len(estilo) == 3:
recomend = []
for k, v in musica_dic.items():
if estilo[0] == k:
recomend.append(v)
elif estilo[1] == k:
recomend.append(v)
elif estilo[2] == k:
recomend.append(v)
return recomend
gustos = ["AA"]
recomendacion(gustos)
'No tenemos recomendación'
Crear una función que entregue una edad como un valor aleatorio entre 15-65 años y educación como otro valor aleatorio entre 0-22, pero tiene que ser menor que la edad.
import random
import numpy as np
#Caso 1: una sola persona
def fun_edad_educ(eda_in, eda_end, edu_in, edu_end):
edad = random.randint(eda_in, eda_end)
educ = random.randint(edu_in, edu_end)
if edad<educ:
educ = random.randint(edu_in, edu_end)
return edad, educ
fun_edad_educ(15, 65, 0, 22) #->que pasa si el if no es suficiente
(43, 7)
#Caso 1: una sola persona
def fun_edad_educ(eda_in, eda_end, edu_in, edu_end):
edad = random.randint(eda_in, eda_end)
educ = random.randint(edu_in, edu_end)
while edad<educ:
edad = random.randint(eda_in, eda_end)
educ = random.randint(edu_in, edu_end)
return edad, educ
fun_edad_educ(15, 65, 50, 100)
(62, 57)
#Caso 3: varias persona
def fun_edad_educ(n, eda_in, eda_end, edu_in, edu_end):
edad_list = []
educ_list = []
for i in range(n):
edad = random.randint(eda_in, eda_end)
educ = random.randint(edu_in, edu_end)
if edad<educ:
educ = random.randint(edu_in, edu_end)
edad_list.append(edad)
educ_list.append(educ)
return np.array(edad_list), np.array(educ_list)
edad_list, educ_list = fun_edad_educ(20, 15, 65, 0, 22)
#Caso 4: varias persona
def fun_edad_educ(n, eda_in, eda_end, edu_in, edu_end):
edad_list = []
educ_list = []
for i in range(n):
edad = random.randint(eda_in, eda_end)
educ = random.randint(edu_in, edu_end)
while edad<educ:
edad = random.randint(eda_in, eda_end)
educ = random.randint(edu_in, edu_end)
edad_list.append(edad)
educ_list.append(educ)
return np.array(edad_list), np.array(educ_list)
edad_list, educ_list = fun_edad_educ(20, 15, 65, 50, 100)
(array([56, 58, 63, 58, 58, 54, 64, 57, 62, 61, 65, 64, 59, 62, 55, 54, 65,
65, 65, 54]),
array([51, 52, 60, 50, 52, 54, 64, 52, 53, 56, 60, 52, 55, 53, 50, 52, 54,
50, 58, 53]))
Crear una función que calcule la experiencia como edad-educación
def fun_exp(edad, educ):
return edad-educ
exp = fun_exp(edad_list, educ_list)
Crear una función que calcule la estimación del ingreso según la ecuación de
Mincer: \(Ln(Y) = \beta_0 + \beta_1 S + \beta_2 Exp + \beta_3 Exp^2\) Donde:
\(S\): años de educación
\(Exp\): experiencia
\(Exp^2\): experiencia al cuadrado
Utilice: \(\beta_0=9.7\), \(\beta_1=0.14\), \(\beta_2=0.07\), \(\beta_3=-0.001\)
def mincer(S, Exp):
β0 = 9.7
β1 = 0.14
β2 = 0.07
β3 = -0.001
return β0 + β1*S + β2*Exp + β3*Exp**2
ln_y = mincer(educ_list, exp)
import matplotlib.pyplot as plt
plt.plot(educ_list, ln_y, 'o')
[<matplotlib.lines.Line2D at 0x7f8d284574c0>]
Actividad 1¶
Instrucciones:¶
Cada pregunta la debe responder en una celda diferente (en total 4 celdas de código).
Antes de cada celda de código debe ir un
markdownque muestre la pregunta que está respondiendo.En la celda de código debe agregar un breve comentario de qué está haciendo.
Mandar el archivo PDF al correo felix.ordonez@usach.cl con el asunto “Actividad 1”.
Fecha de entrega: antes de la clase del 09/11.
En caso que no respete las instrucciones se le descontará puntaje de la nota
Nombre:
Crear una función que entregue una edad como un valor aleatorio entre 15-65 años, educación como otro valor aleatorio entre 0-22 (tiene que ser menor que la edad) y sexo igual a una variable dicotómica (0 o 1) aleatoria.
Crear una función que calcule la experiencia como edad-educación
Crear una función que calcule la estimación del ingreso según la ecuación de Mincer: \(Ln(y)=\beta_0+\beta_1S+\beta_2Exp+\beta_3Exp^2 + \beta_4 Sexo + \beta_5(Sexo*S)\)
Donde:
\(S\): años de educación
\(Exp\): experiencia
\(Exp^2\): experiencia al cuadrado
Utilice: \(\beta_0=9.7\), \(\beta_1=0.15\), \(\beta_2=0.08\), \(\beta_3=-0.0011\), \(\beta_4=-0.15\), \(\beta_5=-0.0136\)
Relice el proceso en una iteración para N = 100 personas, guarde los resultados mediante un diccionario que la llave sea la persona (\(n=1,\cdots,N\)) y el valor sea una lista del tipo: [S, Exp, Exp2, Sexo, Sexo*S, Ln(y)]. Muestre los resultados de su diccionario.
Clase 11-12: Introducción a los gráficos¶
En esta clase vamos introducir una librería para realizar visualizaciones.
Para estas visualizaciones vamos a poder utilizar diferentes typescomo números, textos, listas o diccionarios.
Hoy vamos a revisar la librería matplotlib que abreviamos como plt.
Todo sobre esta librería la pueden encontrar en su página web (link 1): https://matplotlib.org/
Algunos ejemplos simples en el link 2: https://matplotlib.org/stable/tutorials/introductory/pyplot.html
Ejemplo de visualizaciones (no marearse con el código)¶
import numpy as np
import matplotlib.pyplot as plt
# Fixing random state for reproducibility
np.random.seed(19680801)
N = 50
x = np.random.rand(N)
y = np.random.rand(N)
colors = np.random.rand(N)
area = (30 * np.random.rand(N))**2 # 0 to 15 point radii
plt.scatter(x, y, s=area, c=colors, alpha=0.5)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
data = [[ 66386, 174296, 75131, 577908, 32015],
[ 58230, 381139, 78045, 99308, 160454],
[ 89135, 80552, 152558, 497981, 603535],
[ 78415, 81858, 150656, 193263, 69638],
[139361, 331509, 343164, 781380, 52269]]
columns = ('Freeze', 'Wind', 'Flood', 'Quake', 'Hail')
rows = ['%d year' % x for x in (100, 50, 20, 10, 5)]
values = np.arange(0, 2500, 500)
value_increment = 1000
# Get some pastel shades for the colors
colors = plt.cm.BuPu(np.linspace(0, 0.5, len(rows)))
n_rows = len(data)
index = np.arange(len(columns)) + 0.3
bar_width = 0.4
# Initialize the vertical-offset for the stacked bar chart.
y_offset = np.zeros(len(columns))
# Plot bars and create text labels for the table
cell_text = []
for row in range(n_rows):
plt.bar(index, data[row], bar_width, bottom=y_offset, color=colors[row])
y_offset = y_offset + data[row]
cell_text.append(['%1.1f' % (x / 1000.0) for x in y_offset])
# Reverse colors and text labels to display the last value at the top.
colors = colors[::-1]
cell_text.reverse()
# Add a table at the bottom of the axes
the_table = plt.table(cellText=cell_text,
rowLabels=rows,
rowColours=colors,
colLabels=columns,
loc='bottom')
# Adjust layout to make room for the table:
plt.subplots_adjust(left=0.2, bottom=0.2)
plt.ylabel("Loss in ${0}'s".format(value_increment))
plt.yticks(values * value_increment, ['%d' % val for val in values])
plt.xticks([])
plt.title('Loss by Disaster')
plt.show()
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(19680801)
# example data
mu = 100 # mean of distribution
sigma = 15 # standard deviation of distribution
x = mu + sigma * np.random.randn(437)
num_bins = 50
fig, ax = plt.subplots()
# the histogram of the data
n, bins, patches = ax.hist(x, num_bins, density=True)
# add a 'best fit' line
y = ((1 / (np.sqrt(2 * np.pi) * sigma)) *
np.exp(-0.5 * (1 / sigma * (bins - mu))**2))
ax.plot(bins, y, '--')
ax.set_xlabel('Smarts')
ax.set_ylabel('Probability density')
ax.set_title(r'Histogram of IQ: $\mu=100$, $\sigma=15$')
# Tweak spacing to prevent clipping of ylabel
fig.tight_layout()
plt.show()
import matplotlib.pyplot as plt
import numpy as np
np.random.seed(19680801)
data = np.random.randn(2, 100)
fig, axs = plt.subplots(2, 2, figsize=(5, 5))
axs[0, 0].hist(data[0])
axs[1, 0].scatter(data[0], data[1])
axs[0, 1].plot(data[0], data[1])
axs[1, 1].hist2d(data[0], data[1])
plt.show()
Introducción a los gráficos¶
import matplotlib.pyplot as plt
Para hacer un gráfico vamos a usar la función plot y show para mostrar (es como el print() de los gráficos).
Utilizando la lista [1,2,3,4] podemos hacer una línea recta
¿Es de 45°?
y = [1,2,3,4]
plt.plot(y)
plt.show()
Lo anterior es equivalente a graficar
y = [1,2,3,4]
x = [0, 1, 2, 3]
plt.plot(x, y)
plt.show()
Entonces si queremos hacer una línea de 45°
plt.plot(x, x)
plt.show()
Los gŕaficos funcionan como capas, si colocamos un código seguido del otro (sin el plt.show()) se agregan al mismo plot.
y = [1,2,3,4]
plt.plot(y) #No es de 45°
plt.plot(y, y) #Es de 45°
plt.show()
Entonces si queremos graficar (x, y) donde x = [1, 2, …, 10], \(y = 2x^2+1\).
import numpy as np #Importamos la librería numérica
x = np.linspace(1, 10, 10) #Creamos un vector numérico entre 1-10 con 10 elementos
y = 2*x**2 +1 #Creamos la ecuación
plt.plot(x, y) #Graficamos
plt.show()
Otro gráfico y = log(x)
x = np.linspace(1, 100, 1000) #Creamos un vector entre 1-100 con 1000 elementos
y = np.log(x) #Sacamos el logaritmo de cada valor de x
plt.plot(x, y) #Graficamos (x, y)
plt.show()
plt.show()
¿Cómo agregamos títlo y nombres de ejes?
x = np.linspace(1, 100, 1000) #Valores de x
y = np.log(x) #Valores de y
plt.plot(x, y)
plt.title("Gráfico Logaritmo") #título
plt.xlabel("x") #título eje x
plt.ylabel("y") #título eje y
plt.show()
Para agregar una leyenda usamos plt.legend()
plt.plot(x, y)
plt.title("Gráfico Logaritmo") #título
plt.xlabel("x") #título eje x
plt.ylabel("y") #título eje y
plt.legend("A") #Leyenda
plt.show()
Entonces podemos graficar varias situaciones a partir de las diferentes capas.
#Ponderadores
α1 = 0.1
α2 = 0.4
α3 = 1
α4 = 1.5
#Valores de x e y
x = np.linspace(1, 100, 1000)
y1 = np.log(x)*α1
y2 = np.log(x)*α2
y3 = np.log(x)*α3
y4 = np.log(x)*α4
plt.plot(x, y1, label="α1="+str(α1))
plt.plot(x, y2, label="α2="+str(α2))
plt.plot(x, y3, label="α3="+str(α3))
plt.plot(x, y4, label="α4="+str(α4))
plt.title("Gráfico Logaritmo") #título
plt.xlabel("x") #título eje x
plt.ylabel("y") #título eje y
plt.legend()
plt.show()
Gráfico de barra: recordar que los gráficos funcionan como capas
import matplotlib.pyplot as plt
# Datos
Valor = [1, 12, 7, 20, 60]
barras = ('A', 'B', 'C', 'D', 'E')
y_pos = np.arange(len(barras))
# Creamos las barras
plt.bar(y_pos, Valor)
# Creamos los nombres en el eje
plt.xticks(y_pos, barras)
# Mostrar el gráfico
plt.show()
Le podemos cambiar la intensidad del color
# Datos
Valor = [1, 12, 7, 20, 60]
barras = ('A', 'B', 'C', 'D', 'E')
y_pos = np.arange(len(barras))
# Creamos las barras
plt.bar(y_pos, Valor, alpha=0.5) #Con el parámetro alpha cambiamos la intensidad del color
# Creamos los nombres en el eje
plt.xticks(y_pos, barras)
# Mostrar el gráfico
plt.show()
Podemos cambiar el color usando el argumento “color”.
Para ver las opciones de colores pueden revisar el siguiente link 3: https://matplotlib.org/stable/gallery/color/named_colors.html
# Datos
Valor = [1, 12, 7, 20, 60]
barras = ('A', 'B', 'C', 'D', 'E')
y_pos = np.arange(len(barras))
# Creamos las barras
plt.bar(y_pos, Valor, color='red', alpha=0.8) #con "color" modificamos el color
# Creamos los nombres en el eje
plt.xticks(y_pos, barras)
# Mostrar el gráfico
plt.show()
Para modificar la orientación del gráfico usamos “plt.barh” en lugar de “plt.bar” y los nombres de eje ahora se ponen en “plt.yticks”.
# Datos
Valor = [1, 12, 7, 20, 60]
barras = ('A', 'B', 'C', 'D', 'E')
y_pos = np.arange(len(barras))
# Creamos las barras
plt.barh(y_pos, Valor, color='red', alpha=0.8) #con "color" modificamos el color
# Creamos los nombres en el eje
plt.yticks(y_pos, barras)
# Mostrar el gráfico
plt.show()
Con estos ejemplos básicos, junto a un poco de información adicional podemos crear un gráfico de barras para dos grupos diferentes.
Para esto vamos a utilizar el argumento “width” que nos va a permitir separar las barras.
Para ver los otros argumentos de los “plot.bar” pueden ver el siguiente link 4: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.bar.html
Valor1 = [1, 12, 7, 20, 60]
Valor2 = [10, 5, 12, 20, 40]
barras = ('A', 'B', 'C', 'D', 'E')
y_pos = np.arange(len(barras))
bar_width = 0.35
# Creamos las barras
'''barra 1''' #Podemos escribir los elementos del gráfico separados por coma y por saltos de línea
plt.bar(y_pos, Valor1,
bar_width,
color='red',
alpha=0.8,
label = "Caso 1")
'''barra 2'''
plt.bar(y_pos+bar_width, Valor2,
bar_width,
color='green',
alpha=0.6,
label = "Caso 2")
# Creamos los nombres en el eje
plt.xticks(y_pos+bar_width/2, barras)
plt.legend() #Para que nos muestre los labels
# Mostrar el gráfico
plt.show()
Algunas preguntas para seguir utilizando gráficos:
¿Podemos colocar un gráfico dentro de una función?
¿Nos sirven los condicionales para un gráfico?
¿Qué otros tipos de gráficos podemos crear?
¿Nos sirven los loops para simplificar los códigos de un gráfico?
Actividad en clases¶
Usando el ejemplo de Mincer de la clase anterior, vamos a graficar los resultados.
Tenemos las funciones:
fun_edad_educ()
fun_exp()
mincer()
import random
import numpy as np
def fun_edad_educ(n, eda_in, eda_end, edu_in, edu_end):
edad_list = []
educ_list = []
for i in range(n):
edad = random.randint(eda_in, eda_end)
educ = random.randint(edu_in, edu_end)
while edad<educ:
edad = random.randint(eda_in, eda_end)
educ = random.randint(edu_in, edu_end)
edad_list.append(edad)
educ_list.append(educ)
return np.array(edad_list), np.array(educ_list)
def fun_exp(edad, educ):
return edad-educ
def mincer(S, Exp):
β0 = 9.7
β1 = 0.14
β2 = 0.07
β3 = -0.001
return β0 + β1*S + β2*Exp + β3*Exp**2
#Obtener: edad y educación
edad, educ = fun_edad_educ(100, 15, 65, 0, 22)
#Obtener: experiencia
exp = fun_exp(edad, educ)
#Obtener: ln(y)
ln_y = mincer(educ, exp)
Crear un
gráfico de puntos(scatter) entre edad y educación.Crear un
gráfico de puntosentre experiencia (eje horizontal) y ln_y (eje vertical), donde los puntos sean rojos, agregar título de ejes, título de gráfico, y una línea punteada de 45°.Crear un
gráfico de barrascon el promedio, mediana, y desviación estándar de ln_y.Crear un
histogramausando el ln_y.
Clase 13: introducción a los datos¶
En esta clase revisaremos como importar datos, diferentes formatos que podemos utilizar y algunos problemas típicos a la hora del manejo de información.
La librería que vamos a ocupar para el manejo de datos es pandas.
La documentación de
pandasla pueden encontrar en el link 1: https://pandas.pydata.org/docs/La documentación de read_csv la encuentran en el link 2: https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html
Conceptos clave:
Pandas
DataFrame
Delimitador de miles y decimales
Tipo de variable
Index
1. Introducción¶
import pandas as pd
Para importar una base de datos en formato csvvamos a utilizar pd.read_csv(ruta/archivo)
En el caso de Windows llamamos la ruta con doble “\(\backslash \backslash\)”, por ejemplo: “C:\(\backslash \backslash\)Users\(\backslash \backslash\)…”
Vamos a utilizar una base csv del banco central con información de empleo. Lo primero que llama la atención es que la base importa mal debido al delimitador, la base viene con “;” y por default viene “,”.
pd.read_csv("/home/felix/Dropbox/Computational_Economics/Intro_python/2021_S2/Clases/clase13_base1.csv")
| Periodo;1.Total;2.Empleadores;3.Cuenta Propia;4.Asalariados;5.Personal de servicio;6.Familiar no remunerado | ||||||
|---|---|---|---|---|---|---|
| mar.2010;7.156 | 21;318 | 32;1.289 | 68;5.141 | 76;325 | 38;81 | 8 |
| abr.2010;7.198 | 78;324 | 94;1.332 | 33;5.114 | 80;331 | 31;95 | 39 |
| may.2010;7.181 | 90;326 | 95;1.346 | 54;5.080 | 65;328 | 56;99 | 21 |
| jun.2010;7.221 | 58;328 | 03;1.384 | 28;5.074 | 00;327 | 60;107 | 68 |
| jul.2010;7.256 | 52;333 | 82;1.390 | 03;5.081 | 93;339 | 44;111 | 29 |
| ... | ... | ... | ... | ... | ... | ... |
| nov.2020;7.916 | 72;248 | 89;1.568 | 05;5.833 | 68;188 | 43;77 | 66 |
| dic.2020;8.026 | 22;234 | 57;1.588 | 14;5.927 | 28;194 | 91;81 | 32 |
| ene.2021;8.121 | 42;237 | 25;1.610 | 63;6.000 | 74;197 | 43;75 | 36 |
| feb.2021;8.167 | 62;245 | 25;1.634 | 08;6.018 | 35;198 | 73;71 | 20 |
| mar.2021;8.148 | 21;246 | 92;1.646 | 38;5.978 | 29;204 | 48;72 | 14 |
133 rows × 1 columns
Para cambiar el delimitador vamos a usar delimiter
pd.read_csv("/home/felix/Dropbox/Computational_Economics/Intro_python/2021_S2/Clases/clase13_base1.csv", delimiter=";")
| Periodo | 1.Total | 2.Empleadores | 3.Cuenta Propia | 4.Asalariados | 5.Personal de servicio | 6.Familiar no remunerado | |
|---|---|---|---|---|---|---|---|
| 0 | mar.2010 | 7.156,21 | 318,32 | 1.289,68 | 5.141,76 | 325,38 | 81,08 |
| 1 | abr.2010 | 7.198,78 | 324,94 | 1.332,33 | 5.114,80 | 331,31 | 95,39 |
| 2 | may.2010 | 7.181,90 | 326,95 | 1.346,54 | 5.080,65 | 328,56 | 99,21 |
| 3 | jun.2010 | 7.221,58 | 328,03 | 1.384,28 | 5.074,00 | 327,60 | 107,68 |
| 4 | jul.2010 | 7.256,52 | 333,82 | 1.390,03 | 5.081,93 | 339,44 | 111,29 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 128 | nov.2020 | 7.916,72 | 248,89 | 1.568,05 | 5.833,68 | 188,43 | 77,66 |
| 129 | dic.2020 | 8.026,22 | 234,57 | 1.588,14 | 5.927,28 | 194,91 | 81,32 |
| 130 | ene.2021 | 8.121,42 | 237,25 | 1.610,63 | 6.000,74 | 197,43 | 75,36 |
| 131 | feb.2021 | 8.167,62 | 245,25 | 1.634,08 | 6.018,35 | 198,73 | 71,20 |
| 132 | mar.2021 | 8.148,21 | 246,92 | 1.646,38 | 5.978,29 | 204,48 | 72,14 |
133 rows × 7 columns
Si el archivo se encuentra en la misma carpeta que el Jupyter se puede llamar sólo con el nombre del csv.
pd.read_csv("clase13_base1.csv", delimiter=";")
| Periodo | 1.Total | 2.Empleadores | 3.Cuenta Propia | 4.Asalariados | 5.Personal de servicio | 6.Familiar no remunerado | |
|---|---|---|---|---|---|---|---|
| 0 | mar.2010 | 7.156,21 | 318,32 | 1.289,68 | 5.141,76 | 325,38 | 81,08 |
| 1 | abr.2010 | 7.198,78 | 324,94 | 1.332,33 | 5.114,80 | 331,31 | 95,39 |
| 2 | may.2010 | 7.181,90 | 326,95 | 1.346,54 | 5.080,65 | 328,56 | 99,21 |
| 3 | jun.2010 | 7.221,58 | 328,03 | 1.384,28 | 5.074,00 | 327,60 | 107,68 |
| 4 | jul.2010 | 7.256,52 | 333,82 | 1.390,03 | 5.081,93 | 339,44 | 111,29 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 128 | nov.2020 | 7.916,72 | 248,89 | 1.568,05 | 5.833,68 | 188,43 | 77,66 |
| 129 | dic.2020 | 8.026,22 | 234,57 | 1.588,14 | 5.927,28 | 194,91 | 81,32 |
| 130 | ene.2021 | 8.121,42 | 237,25 | 1.610,63 | 6.000,74 | 197,43 | 75,36 |
| 131 | feb.2021 | 8.167,62 | 245,25 | 1.634,08 | 6.018,35 | 198,73 | 71,20 |
| 132 | mar.2021 | 8.148,21 | 246,92 | 1.646,38 | 5.978,29 | 204,48 | 72,14 |
133 rows × 7 columns
El resultado es una estructura del tipo fila-columna que podemos guardar en una variable que llamaremos DataFrame.
Un DataFrame corresponde a una estructura de datos del tipo fila-columna (similar a una hoja de excel) en el que podemos guardar información de diferentes types. Los DataFrame tienen un índice en la primera columna que parte en 0.
Nuestro DataFrame tiene 133 filas y 7 columnas, donde el índice va de 0 a 132.
df = pd.read_csv("clase13_base1.csv", delimiter=";")
2. Accediendo a un DataFrame¶
La primera mirada a nustros datos se la vamos a dar con la función head(), esta nos muestra un resumen de la tabla. Para esto ponemos “nombre del DataFrame”+ “.” + “head()”.
Esto nos va a mostrar las columnas de la base y las primeras 5 filas.
df.head()
| Periodo | 1.Total | 2.Empleadores | 3.Cuenta Propia | 4.Asalariados | 5.Personal de servicio | 6.Familiar no remunerado | |
|---|---|---|---|---|---|---|---|
| 0 | mar.2010 | 7.156,21 | 318,32 | 1.289,68 | 5.141,76 | 325,38 | 81,08 |
| 1 | abr.2010 | 7.198,78 | 324,94 | 1.332,33 | 5.114,80 | 331,31 | 95,39 |
| 2 | may.2010 | 7.181,90 | 326,95 | 1.346,54 | 5.080,65 | 328,56 | 99,21 |
| 3 | jun.2010 | 7.221,58 | 328,03 | 1.384,28 | 5.074,00 | 327,60 | 107,68 |
| 4 | jul.2010 | 7.256,52 | 333,82 | 1.390,03 | 5.081,93 | 339,44 | 111,29 |
Podemos decir específicamente cuántas filas queremos ver colocando el número dentro del paréntesis de head(10).
df.head(10)
| Periodo | 1.Total | 2.Empleadores | 3.Cuenta Propia | 4.Asalariados | 5.Personal de servicio | 6.Familiar no remunerado | |
|---|---|---|---|---|---|---|---|
| 0 | mar.2010 | 7.156,21 | 318,32 | 1.289,68 | 5.141,76 | 325,38 | 81,08 |
| 1 | abr.2010 | 7.198,78 | 324,94 | 1.332,33 | 5.114,80 | 331,31 | 95,39 |
| 2 | may.2010 | 7.181,90 | 326,95 | 1.346,54 | 5.080,65 | 328,56 | 99,21 |
| 3 | jun.2010 | 7.221,58 | 328,03 | 1.384,28 | 5.074,00 | 327,60 | 107,68 |
| 4 | jul.2010 | 7.256,52 | 333,82 | 1.390,03 | 5.081,93 | 339,44 | 111,29 |
| 5 | ago.2010 | 7.289,22 | 333,77 | 1.430,97 | 5.080,20 | 339,49 | 104,79 |
| 6 | sep.2010 | 7.389,47 | 339,06 | 1.477,55 | 5.130,21 | 338,02 | 104,63 |
| 7 | oct.2010 | 7.414,43 | 343,68 | 1.485,61 | 5.150,80 | 331,05 | 103,29 |
| 8 | nov.2010 | 7.503,09 | 347,12 | 1.486,07 | 5.216,86 | 341,96 | 111,08 |
| 9 | dic.2010 | 7.572,32 | 340,32 | 1.486,32 | 5.294,66 | 342,20 | 108,82 |
La función dtypes nos va a describir la información dentro de la base de datos.
df.dtypes
Periodo object
1.Total object
2.Empleadores object
3.Cuenta Propia object
4.Asalariados object
5.Personal de servicio object
6.Familiar no remunerado object
dtype: object
El type object corresponde a un dato del tipo texto, como una palabra. En este caso es poco intuitivo frente al tipo de datos que estamos usando. Deberíamos esperar que la base fuese en su mayoría del tipo numérico (Float, Int).
Para esto podemos especificar dos cosas:
Decimal: usamos el argumento
decimal="separador".Separador de miles: usamos el argumento
thousands="separador"
Esto es relevante porque según la configuración del computador e idioma las bases pueden venir con separadores “.” o “,”. En nuestro caso la base viene con separador de decimal “,” y con separador de miles “.”.
#1. Guarda el DataFrame, muestra las columnas y la cantidad de filas y columnas
#IMportar datos
df = pd.read_csv("clase13_base1.csv", delimiter=";", decimal=",", thousands='.')
#Muestra los tipos
print(df.dtypes)
#Muestra columnas
print(df.columns)
#Mostrar N fila- M columna
print(df.shape)
Periodo object
1.Total float64
2.Empleadores float64
3.Cuenta Propia float64
4.Asalariados float64
5.Personal de servicio float64
6.Familiar no remunerado float64
dtype: object
Index(['Periodo', '1.Total', '2.Empleadores', '3.Cuenta Propia',
'4.Asalariados', '5.Personal de servicio', '6.Familiar no remunerado'],
dtype='object')
(133, 7)
Para ver las columnas del DataFrame usamos columns
df.columns
Index(['Periodo', '1.Total', '2.Empleadores', '3.Cuenta Propia',
'4.Asalariados', '5.Personal de servicio', '6.Familiar no remunerado'],
dtype='object')
Las dimensiones fila-columna las podemos ver mediante shape. Esta viene en formato tupla (fila,columna)
df.shape
(133, 7)
Para ver el final de la tabla podemos usar tail()
df.tail()
| Periodo | 1.Total | 2.Empleadores | 3.Cuenta Propia | 4.Asalariados | 5.Personal de servicio | 6.Familiar no remunerado | |
|---|---|---|---|---|---|---|---|
| 128 | nov.2020 | 7916.72 | 248.89 | 1568.05 | 5833.68 | 188.43 | 77.66 |
| 129 | dic.2020 | 8026.22 | 234.57 | 1588.14 | 5927.28 | 194.91 | 81.32 |
| 130 | ene.2021 | 8121.42 | 237.25 | 1610.63 | 6000.74 | 197.43 | 75.36 |
| 131 | feb.2021 | 8167.62 | 245.25 | 1634.08 | 6018.35 | 198.73 | 71.20 |
| 132 | mar.2021 | 8148.21 | 246.92 | 1646.38 | 5978.29 | 204.48 | 72.14 |
Para revisar una columna en específico podemos usar diferentes mecanismos
#Caso 1
df['Periodo']
#Caso 2
df.Periodo
0 mar.2010
1 abr.2010
2 may.2010
3 jun.2010
4 jul.2010
...
128 nov.2020
129 dic.2020
130 ene.2021
131 feb.2021
132 mar.2021
Name: Periodo, Length: 133, dtype: object
¿Qué pasa cuando el nombre de nuestra columna viene con espacios? ¿Podemos usar el caso 2?
#Funciona
df['3.Cuenta Propia']
#No Funciona
df.'3.Cuenta Propia'
File "<ipython-input-15-3e2cc8594c50>", line 4
df.'3.Cuenta Propia'
^
SyntaxError: invalid syntax
Por esta razón es fundamental que los nombres sean simples, en caso que tengan más de una palabra separar con “_”.
3. Manipulando el DataFrame¶
Lo primero que haremos es modificar el nombre de las variables. Para esto podemos usar el la función rename() y un diccionario con {‘nombre_antiguo’:’nombre_nuevo’}.
df.rename(columns={'1.Total': 'TOT', '2.Empleadores':'EMP', '3.Cuenta Propia':'CP', '4.Asalariados':'ASA', '5.Personal de servicio':'PdS', '6.Familiar no remunerado':'FnR'})
| Periodo | TOT | EMP | CP | ASA | PdS | FnR | |
|---|---|---|---|---|---|---|---|
| 0 | mar.2010 | 7156.21 | 318.32 | 1289.68 | 5141.76 | 325.38 | 81.08 |
| 1 | abr.2010 | 7198.78 | 324.94 | 1332.33 | 5114.80 | 331.31 | 95.39 |
| 2 | may.2010 | 7181.90 | 326.95 | 1346.54 | 5080.65 | 328.56 | 99.21 |
| 3 | jun.2010 | 7221.58 | 328.03 | 1384.28 | 5074.00 | 327.60 | 107.68 |
| 4 | jul.2010 | 7256.52 | 333.82 | 1390.03 | 5081.93 | 339.44 | 111.29 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 128 | nov.2020 | 7916.72 | 248.89 | 1568.05 | 5833.68 | 188.43 | 77.66 |
| 129 | dic.2020 | 8026.22 | 234.57 | 1588.14 | 5927.28 | 194.91 | 81.32 |
| 130 | ene.2021 | 8121.42 | 237.25 | 1610.63 | 6000.74 | 197.43 | 75.36 |
| 131 | feb.2021 | 8167.62 | 245.25 | 1634.08 | 6018.35 | 198.73 | 71.20 |
| 132 | mar.2021 | 8148.21 | 246.92 | 1646.38 | 5978.29 | 204.48 | 72.14 |
133 rows × 7 columns
Si hacemos sólo df.rename() no se modifica el DataFrame, entonces tenemos dos opciones: 1) creamos uno nuevo o 2) modificamos el que ya existe.
#1. Creamos lun DF nuevo
df2 = df.rename(columns={'1.Total': 'TOT', '2.Empleadores':'EMP', '3.Cuenta Propia':'CP', '4.Asalariados':'ASA', '5.Personal de servicio':'PdS', '6.Familiar no remunerado':'FnR'})
#2. Modificamos el que existe
df = df.rename(columns={'1.Total': 'TOT', '2.Empleadores':'EMP', '3.Cuenta Propia':'CP', '4.Asalariados':'ASA', '5.Personal de servicio':'PdS', '6.Familiar no remunerado':'FnR'})
df.head()
| Periodo | TOT | EMP | CP | ASA | PdS | FnR | |
|---|---|---|---|---|---|---|---|
| 0 | mar.2010 | 7156.21 | 318.32 | 1289.68 | 5141.76 | 325.38 | 81.08 |
| 1 | abr.2010 | 7198.78 | 324.94 | 1332.33 | 5114.80 | 331.31 | 95.39 |
| 2 | may.2010 | 7181.90 | 326.95 | 1346.54 | 5080.65 | 328.56 | 99.21 |
| 3 | jun.2010 | 7221.58 | 328.03 | 1384.28 | 5074.00 | 327.60 | 107.68 |
| 4 | jul.2010 | 7256.52 | 333.82 | 1390.03 | 5081.93 | 339.44 | 111.29 |
Una mirada inicial a una variable podemos darla con la función describe(). Esta función nos entrega una resumen estadístico de la variable.
#1. Llamamos una variable df.variable
df.TOT.describe()
#2. Llamamos df['variable']
df['TOT'].describe()
count 133.000000
mean 8187.411504
std 504.204366
min 7073.190000
25% 7844.780000
50% 8202.890000
75% 8535.210000
max 9118.180000
Name: TOT, dtype: float64
Podemos sacar una estadística en particular
print("min:", df.TOT.min())
print("max:", df.TOT.max())
print("mean:", df.TOT.mean())
print("std:", df.TOT.std())
print("count:", df.TOT.count())
min: 7073.19
max: 9118.18
mean: 8187.411503759398
std: 504.20436565714255
count: 133
La variable Periodo sigue siendo del tipo Objeto (texto), podemos crear una variable del tipo fecha. Para esto vamos a hacer dos cosas: 1) crear una variable en formato fecha y 2) agregar esta variable al DataFrame.
Para crear una variable del tipo fecha podemos usar la función
date_range(fecha_inicio, periodos, frecuencia). En el siguiente link (link 3) encuentran detalle de como variables del tipo fecha en un DataFrame: https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html.Para anexar una variable al DataFrame colocamos
df['nombre_variable'] = variable.
#Creamos una variable del tipo fecha con la función
Date = pd.date_range("2010-03-01", periods=133, freq="M")
#Anexamos la variable nueva
df['Date'] = Date
#Vemos el resultado
df.dtypes
Periodo object
TOT float64
EMP float64
CP float64
ASA float64
PdS float64
FnR float64
Date datetime64[ns]
dtype: object
Vamos a guardar los meses y años por separados en el DataFrame. Para esto utilizamos DatetimeIndex (abreviamos dt) que nos permite extraer el segundos/dia/mes/año de una variable del tipo datetime, por ejemplo usando month y year.
#Guardamos el mes en una variable
df['mes'] = df['Date'].dt.month
#Guardamos el año en una variable
df['year'] = df['Date'].dt.year
#Vemos el resultado
print(df.dtypes)
df.head()
Periodo object
TOT float64
EMP float64
CP float64
ASA float64
PdS float64
FnR float64
Date datetime64[ns]
mes int64
year int64
dtype: object
| Periodo | TOT | EMP | CP | ASA | PdS | FnR | Date | mes | year | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | mar.2010 | 7156.21 | 318.32 | 1289.68 | 5141.76 | 325.38 | 81.08 | 2010-03-31 | 3 | 2010 |
| 1 | abr.2010 | 7198.78 | 324.94 | 1332.33 | 5114.80 | 331.31 | 95.39 | 2010-04-30 | 4 | 2010 |
| 2 | may.2010 | 7181.90 | 326.95 | 1346.54 | 5080.65 | 328.56 | 99.21 | 2010-05-31 | 5 | 2010 |
| 3 | jun.2010 | 7221.58 | 328.03 | 1384.28 | 5074.00 | 327.60 | 107.68 | 2010-06-30 | 6 | 2010 |
| 4 | jul.2010 | 7256.52 | 333.82 | 1390.03 | 5081.93 | 339.44 | 111.29 | 2010-07-31 | 7 | 2010 |
Podemos agrupar una variable mediante groupby. Luego podemos aplicar funciones básicas como mean(), std(), sum(), etc.
df_agrupado = df.groupby('year')
df_agrupado.mean()
| TOT | EMP | CP | ASA | PdS | FnR | mes | |
|---|---|---|---|---|---|---|---|
| year | |||||||
| 2010 | 7318.352000 | 333.601000 | 1410.938000 | 5136.587000 | 334.501000 | 102.726000 | 7.5 |
| 2011 | 7676.545833 | 349.602500 | 1488.466667 | 5382.360833 | 359.097500 | 97.016667 | 6.5 |
| 2012 | 7858.610833 | 323.438333 | 1460.165833 | 5626.480000 | 353.575000 | 94.954167 | 6.5 |
| 2013 | 8023.047500 | 334.418333 | 1484.029167 | 5766.081667 | 336.561667 | 101.956667 | 6.5 |
| 2014 | 8150.107500 | 338.969167 | 1569.675000 | 5800.595833 | 336.685000 | 104.185000 | 6.5 |
| 2015 | 8273.739167 | 344.422500 | 1593.640833 | 5919.330833 | 319.370833 | 96.973333 | 6.5 |
| 2016 | 8391.921667 | 334.027500 | 1686.861667 | 5945.020000 | 330.251667 | 95.760000 | 6.5 |
| 2017 | 8574.332500 | 371.210833 | 1777.026667 | 6008.260833 | 323.455000 | 94.375833 | 6.5 |
| 2018 | 8773.940000 | 363.481667 | 1800.942500 | 6185.576667 | 323.193333 | 100.750000 | 6.5 |
| 2019 | 8953.679167 | 368.760000 | 1855.963333 | 6320.787500 | 319.305833 | 88.863333 | 6.5 |
| 2020 | 7932.822500 | 274.867500 | 1495.655000 | 5878.350000 | 214.355000 | 69.597500 | 6.5 |
| 2021 | 8145.750000 | 243.140000 | 1630.363333 | 5999.126667 | 200.213333 | 72.900000 | 2.0 |
Lo anterior podemos hacerlo sobre una o un grupo de variables específicas. Para esto hacemos lo siguiente:
Seleccionamos las variablers sobre las que vamos a trabajar mediante una lista: df[[‘TOT’, ‘year’]]. Tiene que estar la variable sobre la que quiero tener el análisis (TOT) y la que voy a agrupar (year).
Aplicamos la función para agrupar y la variable: groupby(‘year’).
df_agrupado = df[['TOT', 'year']].groupby('year')
df_agrupado.mean()
| TOT | |
|---|---|
| year | |
| 2010 | 7318.352000 |
| 2011 | 7676.545833 |
| 2012 | 7858.610833 |
| 2013 | 8023.047500 |
| 2014 | 8150.107500 |
| 2015 | 8273.739167 |
| 2016 | 8391.921667 |
| 2017 | 8574.332500 |
| 2018 | 8773.940000 |
| 2019 | 8953.679167 |
| 2020 | 7932.822500 |
| 2021 | 8145.750000 |
Si analizamos el resultado de df_agrupado.mean() tiene dos elementos:
index: variable sobre la que se agrupó, esta la llamamos con
.indexVariables relevantes: sobre las que hicimos el análisis, en este caso TOT. La llamamos con [‘TOT’]
#Index
print("index:", df_agrupado.mean().index)
#TOT
print("TOT:", df_agrupado.mean()['TOT'])
index: Int64Index([2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020,
2021],
dtype='int64', name='year')
TOT: year
2010 7318.352000
2011 7676.545833
2012 7858.610833
2013 8023.047500
2014 8150.107500
2015 8273.739167
2016 8391.921667
2017 8574.332500
2018 8773.940000
2019 8953.679167
2020 7932.822500
2021 8145.750000
Name: TOT, dtype: float64
import matplotlib.pyplot as plt
x = df_agrupado.mean().index
y = df_agrupado.mean()['TOT']
plt.bar(x, y)
plt.show()
Con esto podemos empezar a utilizar una base de datos y mostrar algunos resultados!
Para leer datos de excel podemos usar
pd.read_excel.Para leer datos de stata podemos usar
pd.read_stata.
df_agrupado = df[['TOT', 'year']].groupby('year')
df_agrupado.mean()
| TOT | |
|---|---|
| year | |
| 2010 | 7318.352000 |
| 2011 | 7676.545833 |
| 2012 | 7858.610833 |
| 2013 | 8023.047500 |
| 2014 | 8150.107500 |
| 2015 | 8273.739167 |
| 2016 | 8391.921667 |
| 2017 | 8574.332500 |
| 2018 | 8773.940000 |
| 2019 | 8953.679167 |
| 2020 | 7932.822500 |
| 2021 | 8145.750000 |
df_agrupado = df[['TOT', 'year']].groupby('year')
# df_agrupado.head()
Clase 14: continuación con los datos¶
En esta clase vamos a continuar con el uso de pandas. Veremos:
Consultas SQL
Qué es?
Select
Where
Join
Union
Update
Delete
Ejercicios
1. Repaso¶
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
Para el ejemplo de esta clase vamos a usar una pequeña base llamada tips que tiene a disposición la librería pandas.
#Podemos llamar la librería con el siguiente url
url = ("https://raw.github.com/pandas-dev"
"/pandas/master/pandas/tests/io/data/csv/tips.csv")
#Creamos el DataFrame
tips = pd.read_csv(url)
#Revisamos el contenido
tips.head(10)
| total_bill | tip | sex | smoker | day | time | size | |
|---|---|---|---|---|---|---|---|
| 0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
| 1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
| 2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
| 3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
| 4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
| 5 | 25.29 | 4.71 | Male | No | Sun | Dinner | 4 |
| 6 | 8.77 | 2.00 | Male | No | Sun | Dinner | 2 |
| 7 | 26.88 | 3.12 | Male | No | Sun | Dinner | 4 |
| 8 | 15.04 | 1.96 | Male | No | Sun | Dinner | 2 |
| 9 | 14.78 | 3.23 | Male | No | Sun | Dinner | 2 |
Vamos a crear una función que nos permita visualizar información del DataFrame
#Declaramos la función y el nombre del input
def grafico1(DF):
#Definimos los datos a usar
data1 = DF[['total_bill', 'size']].groupby('size').mean()
plt.bar(data1.index, data1.total_bill)
plt.xlabel("Tamaño de la mesa")
plt.ylabel("Promedio de la cuenta")
#Llamamos la función y le damos el input
grafico1(tips)
#Declaramos la función y el nombre del input
def grafico2(DF):
#Definimos los datos
x = DF.total_bill
y = DF.tip
#Gráfico de puntos (scatter)
plt.scatter(x, y)
plt.xlabel("Total cuenta")
plt.ylabel("Propina")
#Gráfico de línea
m, b = np.polyfit(x, y, 1) #Sacar la pendiente y el intercepto de y(x)
plt.plot(x, m*x + b, color='r')
#Llamamos la función y le damos el input
grafico2(tips)
Y si la función la queremos con dos input?
#Declaramos la función y el nombre del input
def grafico2(x, y):
#Gráfico de puntos (scatter)
plt.scatter(x, y)
plt.xlabel("Total cuenta")
plt.ylabel("Propina")
#Gráfico de línea
m, b = np.polyfit(x, y, 1) #Sacar la pendiente y el intercepto de y(x)
plt.plot(x, m*x + b, color='r')
#Creamos las variables que vamos a usar como input
x = tips.total_bill
y = tips.tip
#Hacemos el gráfico
grafico2(x, y)
Si queremos guardar la diferencia entre las filas de una variable del set de datos, podemos por ejemplo usar un for
#Definimos la variable a utilizar
var = tips.total_bill
#Creamos la lista donde vamos a guardar los datos
lista = []
#Realizamos el lopp: desde el segundo valor hasta el último (1, n)
for i in range(1, len(var)):
lista.append(var[i]-var[i-1]) #Sacamos la diferencia
print(var[0:10])
print(lista[0:10])
0 16.99
1 10.34
2 21.01
3 23.68
4 24.59
5 25.29
6 8.77
7 26.88
8 15.04
9 14.78
Name: total_bill, dtype: float64
[-6.649999999999999, 10.670000000000002, 2.669999999999998, 0.9100000000000001, 0.6999999999999993, -16.52, 18.11, -11.84, -0.2599999999999998, -4.51]
Otra forma es usar la función diff. El siguiente link muestra en detalle cómo usar la función:
https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.diff.html
#si queremos sacar la diferencia de una variable definimos el DataFrame.nombre_variable.diff()
print(tips.total_bill.diff().head())
#Tambien podemos especificar los periodos para hacer la diferencia
print(tips.total_bill.diff(periods=3).head())
#Podemos cambiar el sentido de la diferencia (ascendente o descendente)
print(tips.total_bill.diff(periods=-3).head())
0 NaN
1 -6.65
2 10.67
3 2.67
4 0.91
Name: total_bill, dtype: float64
0 NaN
1 NaN
2 NaN
3 6.69
4 14.25
Name: total_bill, dtype: float64
0 -6.69
1 -14.25
2 -4.28
3 14.91
4 -2.29
Name: total_bill, dtype: float64
2. Consultas SQL¶
SQL (por su nombre en inglés) es un lenguaje de programación utilizado para trabajar con bases relacionales. Este lenguaje nos permite recuperar de forma simple información de bases de datos donde tenemos bases que pueden estar relacionadas mediante alguna variable. Por ejemplo:
Podemos tener información de diferentes fuentes, planillas de costos, ingresos, compras, etc. y buscar vincular esta información para hacer análisis, presentar información o realizar cálculos específico.
El objetivo de esta clase no es SQL, sino la forma de trabajar este lenguaje. En python podemos usar pandas para replicar el trabajo con bases de datos relacionales.
Select¶
El objetivo es seleccionar un set de información específico
#Ponemos el DataFrame y las variables específicas que queremos
#Ojo que va "DataFrame[]" y dentro del paréntesis van las variables dentro de un "[]"
tips[["total_bill", "tip", "smoker", "time"]].head(5)
| total_bill | tip | smoker | time | |
|---|---|---|---|---|
| 0 | 16.99 | 1.01 | No | Dinner |
| 1 | 10.34 | 1.66 | No | Dinner |
| 2 | 21.01 | 3.50 | No | Dinner |
| 3 | 23.68 | 3.31 | No | Dinner |
| 4 | 24.59 | 3.61 | No | Dinner |
Para agregar un nueva variable según un ratio podemos usar DataFrame.assign()
tips.assign(tip_rate=tips["tip"] / tips["total_bill"]).head(5)
| total_bill | tip | sex | smoker | day | time | size | tip_rate | |
|---|---|---|---|---|---|---|---|---|
| 0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 | 0.059447 |
| 1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 | 0.160542 |
| 2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 | 0.166587 |
| 3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 | 0.139780 |
| 4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 | 0.146808 |
Where¶
Usamos este tipo de consulta para seleccionar una información en específico, por ejemplo cuando la variable time es igual a Diner
#La sintaxis es DataFrame[DataFrame[Variable] == Condicion]
#En resumen le estamos diciendo DataFrame[Variable == Condicion], donde Variable=DataFrame[Variable]
tips[tips["time"] == "Dinner"].head(5)
| total_bill | tip | sex | smoker | day | time | size | |
|---|---|---|---|---|---|---|---|
| 0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
| 1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
| 2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
| 3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
| 4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
Podemos ver si se cumple una condición como verdadero/falso y podemos usar la función value_counts() para ver cuántas veces se cumple o no
#Creamos una variable que guarde si se cumple la condición
variable_condicion = tips["time"] == "Dinner"
#Evaluamos cuantas veces se cumple la condición con la función value_counts()
variable_condicion.value_counts()
True 176
False 68
Name: time, dtype: int64
Luego, podemos revisar el DataFrame donde se cumpla la condición que establecimos previamente.
tips[variable_condicion].head(5)
| total_bill | tip | sex | smoker | day | time | size | |
|---|---|---|---|---|---|---|---|
| 0 | 16.99 | 1.01 | Female | No | Sun | Dinner | 2 |
| 1 | 10.34 | 1.66 | Male | No | Sun | Dinner | 3 |
| 2 | 21.01 | 3.50 | Male | No | Sun | Dinner | 3 |
| 3 | 23.68 | 3.31 | Male | No | Sun | Dinner | 2 |
| 4 | 24.59 | 3.61 | Female | No | Sun | Dinner | 4 |
Podemos seleccionar más de una condición usando & (and) or | (or)
Por ejemplo, seleccionamos cuando time=Dinner y cuando tip>5.
#LLamamos el DataFrame[variable1 == condicion1 & variable2 >condicion2]
tips[(tips["time"] == "Dinner") & (tips["tip"] > 5.00)]
| total_bill | tip | sex | smoker | day | time | size | |
|---|---|---|---|---|---|---|---|
| 23 | 39.42 | 7.58 | Male | No | Sat | Dinner | 4 |
| 44 | 30.40 | 5.60 | Male | No | Sun | Dinner | 4 |
| 47 | 32.40 | 6.00 | Male | No | Sun | Dinner | 4 |
| 52 | 34.81 | 5.20 | Female | No | Sun | Dinner | 4 |
| 59 | 48.27 | 6.73 | Male | No | Sat | Dinner | 4 |
| 116 | 29.93 | 5.07 | Male | No | Sun | Dinner | 4 |
| 155 | 29.85 | 5.14 | Female | No | Sun | Dinner | 5 |
| 170 | 50.81 | 10.00 | Male | Yes | Sat | Dinner | 3 |
| 172 | 7.25 | 5.15 | Male | Yes | Sun | Dinner | 2 |
| 181 | 23.33 | 5.65 | Male | Yes | Sun | Dinner | 2 |
| 183 | 23.17 | 6.50 | Male | Yes | Sun | Dinner | 4 |
| 211 | 25.89 | 5.16 | Male | Yes | Sat | Dinner | 4 |
| 212 | 48.33 | 9.00 | Male | No | Sat | Dinner | 4 |
| 214 | 28.17 | 6.50 | Female | Yes | Sat | Dinner | 3 |
| 239 | 29.03 | 5.92 | Male | No | Sat | Dinner | 3 |
#La condición "o" la llamamos con el símbolo "|""
tips[(tips["size"] >= 5) | (tips["total_bill"] > 45)]
| total_bill | tip | sex | smoker | day | time | size | |
|---|---|---|---|---|---|---|---|
| 59 | 48.27 | 6.73 | Male | No | Sat | Dinner | 4 |
| 125 | 29.80 | 4.20 | Female | No | Thur | Lunch | 6 |
| 141 | 34.30 | 6.70 | Male | No | Thur | Lunch | 6 |
| 142 | 41.19 | 5.00 | Male | No | Thur | Lunch | 5 |
| 143 | 27.05 | 5.00 | Female | No | Thur | Lunch | 6 |
| 155 | 29.85 | 5.14 | Female | No | Sun | Dinner | 5 |
| 156 | 48.17 | 5.00 | Male | No | Sun | Dinner | 6 |
| 170 | 50.81 | 10.00 | Male | Yes | Sat | Dinner | 3 |
| 182 | 45.35 | 3.50 | Male | Yes | Sun | Dinner | 3 |
| 185 | 20.69 | 5.00 | Male | No | Sun | Dinner | 5 |
| 187 | 30.46 | 2.00 | Male | Yes | Sun | Dinner | 5 |
| 212 | 48.33 | 9.00 | Male | No | Sat | Dinner | 4 |
| 216 | 28.15 | 3.00 | Male | Yes | Sat | Dinner | 5 |
Muchas veces los datos vienen con información vacía o nula. En pandas existe el tipo NaN que significa Not a Number (valores faltantes). Para seleccionar este tipo de datos (o excluirlos) podemos usar isna() (o notna()).
Para ejemplificar lo anterio vamos a crear un pequeño dataframe con este tipo de datos con np.NaN.
ej_null = pd.DataFrame({"col1": ["A", "B", np.NaN, "C", "D"], "col2": ["F", np.NaN, "G", "H", "I"]})
ej_null.head()
| col1 | col2 | |
|---|---|---|
| 0 | A | F |
| 1 | B | NaN |
| 2 | NaN | G |
| 3 | C | H |
| 4 | D | I |
Seleccionamos el dataframe cuando la columna 2 tiene valores del tipo NaN
ej_null[ej_null["col2"].isna()]
| col1 | col2 | |
|---|---|---|
| 1 | B | NaN |
O cuando la columna 1 no tiene valores del tipo NaN
ej_null[ej_null["col1"].notna()]
| col1 | col2 | |
|---|---|---|
| 0 | A | F |
| 1 | B | NaN |
| 3 | C | H |
| 4 | D | I |
Group by¶
Las clases anteriores vimos algunos ejemplos de como usar la función groupby(). Por ejemplo, si queremos agrupar por sexo y saber el número de tips podemos hacer lo siguiente
#Si agrupamos por sexo y nos cuenta todo el set de datos tendremos información irrelevante de sobra
print(tips.groupby("sex").count())
#Podemos seleccionar la información específica que queremos
print(tips[['tip', 'sex']].groupby("sex").count())
total_bill tip smoker day time size
sex
Female 87 87 87 87 87 87
Male 157 157 157 157 157 157
tip
sex
Female 87
Male 157
#O una forma más simple
print(tips.groupby("sex").size())
sex
Female 87
Male 157
dtype: int64
Una diferencia importante entre estos dos métodos (count() vs size()) es que el count() se aplica sobre todas las variables y no incluye los not null, mientras que size() da el total. Si usamos el dataframe del ejemplo anterior:
print(ej_null.groupby('col1').size())
print(ej_null.groupby('col1').count())
col1
A 1
B 1
C 1
D 1
dtype: int64
col2
col1
A 1
B 0
C 1
D 1
Podemos hacer multiples operaciones usando la función agg(). Por ejemplo podemos agrupar por día, y que realice el promedio ‘tip’, junto con la cantidad de días.
La sintaxis es DataFrame.groupby(“Variable a agrupar).agg({“variable1”:operacion, “variable2”:operacion})
tips.groupby("day").agg({"tip": np.mean, "day": np.size})
| tip | day | |
|---|---|---|
| day | ||
| Fri | 2.734737 | 19 |
| Sat | 2.993103 | 87 |
| Sun | 3.255132 | 76 |
| Thur | 2.771452 | 62 |
Para agrupar por mas de una variable usamos una lista dentro del groupby y luego la operación que queremos con agg().
tips.groupby(["smoker", "day"]).agg({"tip": [np.size, np.mean]})
| tip | |||
|---|---|---|---|
| size | mean | ||
| smoker | day | ||
| No | Fri | 4.0 | 2.812500 |
| Sat | 45.0 | 3.102889 | |
| Sun | 57.0 | 3.167895 | |
| Thur | 45.0 | 2.673778 | |
| Yes | Fri | 15.0 | 2.714000 |
| Sat | 42.0 | 2.875476 | |
| Sun | 19.0 | 3.516842 | |
| Thur | 17.0 | 3.030000 | |
Join¶
Una función del tipo join se utiliza para juntar bases de datos mediante alguna variable en común.
Los tipos de join más usados son:
Para nuestro ejemplo vamos a crear dos DataFrame que van a compartir informacion y que vamos a ir vinculando según los diferentes tipos de join.
df1 = pd.DataFrame({"key": ["A", "B", "C", "D"], "value": np.random.randn(4)})
df2 = pd.DataFrame({"key": ["B", "D", "D", "E"], "value": np.random.randn(4)})
print(df1.head())
print(df2.head())
key value
0 A -0.187041
1 B -0.157632
2 C -0.535480
3 D 0.057931
key value
0 B -0.040069
1 D 0.592890
2 D 0.649470
3 E 0.023413
Inner Join¶
Juntamos dos Bases usando la llave en ambas tablas. En nuestro ejemplo la llave (key) que se encuentra en ambas tablas corresponden a: B y D. Entonces vamos a excluir A, C y E.
Sin embargo, en la tabla 2 la llave D está dos veces, por lo que nuestra tabla final va a incluir este resultado la cantidad de veces que se encuentre en la tabla 1 y tabla 2.
pd.merge(df1, df2, on="key")
| key | value_x | value_y | |
|---|---|---|---|
| 0 | B | -0.157632 | -0.040069 |
| 1 | D | 0.057931 | 0.592890 |
| 2 | D | 0.057931 | 0.649470 |
Left outher join¶
Este tipo de consulta se usa cuando queremos mostrar toda la información de una tabla y sólo la información de la segunda tabla cuando se condicen las llaves
pd.merge(df1, df2, on="key", how="left")
| key | value_x | value_y | |
|---|---|---|---|
| 0 | A | -0.187041 | NaN |
| 1 | B | -0.157632 | -0.040069 |
| 2 | C | -0.535480 | NaN |
| 3 | D | 0.057931 | 0.592890 |
| 4 | D | 0.057931 | 0.649470 |
Right Join¶
Nos muestra todo lo de la tabla de la derecha y sólo los valores de la izquierda cuando coincide la llave.
pd.merge(df1, df2, on="key", how="right")
| key | value_x | value_y | |
|---|---|---|---|
| 0 | B | -0.157632 | -0.040069 |
| 1 | D | 0.057931 | 0.592890 |
| 2 | D | 0.057931 | 0.649470 |
| 3 | E | NaN | 0.023413 |
Full Join¶
Cuando queremos mostrar todos los datos de ambos dataframe
pd.merge(df1, df2, on="key", how="outer")
| key | value_x | value_y | |
|---|---|---|---|
| 0 | A | -0.187041 | NaN |
| 1 | B | -0.157632 | -0.040069 |
| 2 | C | -0.535480 | NaN |
| 3 | D | 0.057931 | 0.592890 |
| 4 | D | 0.057931 | 0.649470 |
| 5 | E | NaN | 0.023413 |
Union¶
Usamos esta consulta cuando queremos agregar dos tablas o bases de datos.
Por ejemplo, si creamos dos DataFrames con ciudad y ranking en calidad de vida
df1 = pd.DataFrame({"ciudad": ["Valdivia", "Santiago", "Valparaiso"], "rank": range(1, 4)})
df2 = pd.DataFrame({"ciudad": ["Iquique", "Puerto Montt", "Valdivia"], "rank": [5, 4, 1]})
print(df1)
print(df2)
ciudad rank
0 Valdivia 1
1 Santiago 2
2 Valparaiso 3
ciudad rank
0 Iquique 5
1 Puerto Montt 4
2 Valdivia 1
Los podemos unir usando la función concat
pd.concat([df1, df2])
| ciudad | rank | |
|---|---|---|
| 0 | Valdivia | 1 |
| 1 | Santiago | 2 |
| 2 | Valparaiso | 3 |
| 0 | Iquique | 5 |
| 1 | Puerto Montt | 4 |
| 2 | Valdivia | 1 |
Para eliminar los duplicados podemos usar drop_duplicates
df3 = pd.concat([df1, df2]).drop_duplicates()
print(df3)
ciudad rank
0 Valdivia 1
1 Santiago 2
2 Valparaiso 3
0 Iquique 5
1 Puerto Montt 4
Update¶
Cuando queremos actualizar una variable debemos definir una condición y un nuevo valor. Esto lo podemos hacer para variables numéricas o variables de texto. Para esto usamos la función loc
df3.loc[df3["ciudad"] == "Puerto Montt", "ciudad"] = "Pto. Montt"
print(df3)
ciudad rank
0 Valdivia 1
1 Santiago 2
2 Valparaiso 3
0 Iquique 5
1 Pto. Montt 4
Delete¶
Para eliminar un valor también vamos a usar la función loc. Vamos a definir una condición que no se cumple (!=) y con ella excluir un valor en particular. Por ejemplo, podemos sacar de la tabla cuando la ciudad es Iquique.
df3 = df3.loc[df3["ciudad"] != "Iquique"]
print(df3)
ciudad rank
0 Valdivia 1
1 Santiago 2
2 Valparaiso 3
1 Pto. Montt 4
3. Ejercicios¶
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
nombre = pd.read_excel("ejemplo_sql.xlsx", sheet_name='nombre', thousands=",")
edad = pd.read_excel("ejemplo_sql.xlsx", sheet_name='edad', thousands=",")
almuerzo = pd.read_excel("ejemplo_sql.xlsx", sheet_name='Almuerzo', thousands=",")
print(nombre.head())
print(edad.head())
print(almuerzo.head())
Nombre id
0 Juan 1
1 Andrea 2
2 Ramón 3
3 Valentina 4
id Edad
0 1 10
1 2 25
2 3 60
3 4 55
id dia hora almuerzo
0 1 Lunes 12 pastel de papas
1 2 Lunes 13 porotos
2 3 Lunes 14 lentejas
3 4 Lunes 12 pescado
4 1 Martes 14 ensalada
Seleccionar del dataframe nombre cuando es igual a Valentina. Guardar el id en una variable
id_valentina.
id = nombre[nombre["Nombre"] == "Valentina"].id
Usando el dataframe de almuerzo agrupar por día=lunes y ver hora promedio de almuerzo.
df_lunes = almuerzo[almuerzo["dia"] == "Lunes"]
df_lunes[["dia", "hora"]].groupby("dia").mean()
| hora | |
|---|---|
| dia | |
| Lunes | 12.75 |
Graficar el promedio de hora de almuerzo por día. Usar un gráfico de barras.
x = almuerzo[["dia", "hora"]].groupby("dia").mean().index
y = almuerzo[["dia", "hora"]].groupby("dia").mean()
plt.bar(x, y.hora)
plt.ylabel("Promedio hora de almuerzo")
plt.show()
Usando las funciones del tipo join ver:
¿Qué almorzó Juan en la semana?
¿A qué hora y qué almorzó Andrea el martes?
Crear dataframe
df_totalcon las variables id, Nombre, Edad, dia, hora y almuerzo.
#Inner join: Almuerzo de juan
df = pd.merge(nombre, almuerzo, on="id", how="outer")
df_juan = df[["Nombre", "almuerzo"]][df.Nombre == "Juan"]
print(df_juan)
#Andrea
df_andrea = df[["Nombre", "almuerzo"]][(df.Nombre == "Andrea") & (df.dia=="Martes")]
print(df_andrea)
#Data Frame total
df_total = pd.merge(nombre, edad, on="id", how="outer")
df_total = pd.merge(df_total, almuerzo, on="id",how="outer")
print(df_total)
Nombre almuerzo
0 Juan pastel de papas
1 Juan ensalada
2 Juan garbanzos
Nombre almuerzo
4 Andrea NaN
Nombre id Edad dia hora almuerzo
0 Juan 1 10 Lunes 12 pastel de papas
1 Juan 1 10 Martes 14 ensalada
2 Juan 1 10 Miércoles 16 garbanzos
3 Andrea 2 25 Lunes 13 porotos
4 Andrea 2 25 Martes 14 NaN
5 Andrea 2 25 Miércoles 13 cazuela
6 Ramón 3 60 Lunes 14 lentejas
7 Ramón 3 60 Martes 13 asado
8 Ramón 3 60 Miércoles 14 NaN
9 Valentina 4 55 Lunes 12 pescado
10 Valentina 4 55 Martes 15 NaN
11 Valentina 4 55 Miércoles 14 NaN
¿Cuántas observaciones tiene el
df_total?
df_total.id.count()
12
¿Qué variables tienen NaN y cuántos NaN hay?
#Variables que tienen NaN
#Definimos una variable que evalúe si una variable tiene NaN -> print esta variable tiene NaN
def NA(df):
if df.Nombre.isna().any() == True: #Ocupamos la función any() para comparar cada valor de la variable igual a la condición
print("Nombre tiene NaN")
elif df.id.isna().any() == True:
print("id tiene NaN")
elif df.Edad.isna().any() == True:
print("Edad tiene NaN")
elif df.id.isna().any() == True:
print("id tiene NaN")
elif df.dia.isna().any() == True:
print("dia tiene NaN")
elif df.hora.isna().any() == True:
print("hora tiene NaN")
elif df.almuerzo.isna().any() == True:
print("almuerzo tiene NaN")
#Evaluamos la función
NA(df_total)
#Cuántos NaN?
#Sabemos que sólo almuerzo tiene NaN
print("La variable almuerzo tiene " + str(df_total[df_total["almuerzo"].isna()].id.count()) + " NaN." )
almuerzo tiene NaN
La variable almuerzo tiene 4 NaN.
Crear un nuevo dataframe excluyendo los NaN
condicion = df_total.almuerzo.notna() == True
df_sinNaN = df_total[condicion]
print(df_sinNaN)
Nombre id Edad dia hora almuerzo
0 Juan 1 10 Lunes 12 pastel de papas
1 Juan 1 10 Martes 14 ensalada
2 Juan 1 10 Miércoles 16 garbanzos
3 Andrea 2 25 Lunes 13 porotos
5 Andrea 2 25 Miércoles 13 cazuela
6 Ramón 3 60 Lunes 14 lentejas
7 Ramón 3 60 Martes 13 asado
9 Valentina 4 55 Lunes 12 pescado
Clase 15: gráficos pro con Plotly¶
En esta clase usaremos la libería plotly para ver visualizaciones y tablas.
Plotly es un paquete potente que permite realizar gráficos interactivos de gran calidad visual.
Veremos:
Cómo instalar
Tablas
Gráfico de líneas
Gráfico de puntos (scatter)
Gráfico de barras
Gráfico de torta
Gráfico de burbujas
Mapas de calor
Histogramas
Gráficos de error
Bráfico de cajas
1. Introducción¶
La librería plotly es una librería de python open-source que soporta más de 40 tipos de gráficos interactivos, en el ámbito estadístico, financiero, geográfico, científico, etc.
Esta librería requiere algunos pasos adicionales en su instalación con respecto a otras librerías.
El detalle de la instalación lo pueden encontrar en el siguiente link: https://plotly.com/python/getting-started/
Pasos para instalar plotly:
Abrir el Compand Prompt en Anaconda (pantalla negra). Los siguientes códigos los debe colocar en esta terminal.
Pueden instalar mediante pip o conda:
pip install plotly==4.14.3
conda install -c plotly plotly=4.14.3
Si van a trabajar desde Jupyter Notebook deben instlar los siguientes paquetes adicionales usando pip o conda:
pip install “notebook>=5.3” “ipywidgets>=7.5”
conda install “notebook>=5.3” “ipywidgets>=7.5”
Si trabajan con JupyterLab deben instalar usando pip o conda:
pip install jupyterlab “ipywidgets>=7.5”
conda install jupyterlab “ipywidgets>=7.5”
Instalar
nodejs:Chequear si tiene instalado el programa. En el Command Prompt ejecutar node -v, le va a mostrar si tiene instalado el programa y qué versión tiene. Si lo tiene instalado saltar los siguientes dos pasos.
Descargar el instalador para su sistema operativo: https://nodejs.org/es/download/
Ejecutar el archivo instalado
Una vez tenga chequeado que tiene instalado el
nodejsejecutar:jupyter labextension install jupyterlab-plotly@4.14.3
Ver si la instalación arroja algún error!
Una vez realizados estos 6 pasos, debería poder ejecutar el siguiente código en un JupyterLab y le debería mostrar un gráfico de barras.
import plotly.graph_objects as go
fig = go.Figure(data=go.Bar(y=[2, 3, 1]))
fig.show()
2. Tablas¶
go.Table nos va a entragar un interfaz para visualizar datos mediante tablas, en formato de filas-columnas.
Estas tablas las podemos enchular según las necesidades del caso.
#Importar librería
import plotly.graph_objects as go
#Valores a mostrar
encabezado = ['A Scores', 'B Scores']
valores = [[100, 90, 80, 90], [95, 85, 75, 95]]
#Crear figura
#1. llamar librería y función: go.Figure()
#2. Definir datos: data=[]
#3. Usar go.Table() para definir encabezado (header) y valores(cells)
#4. Guardamos el resultado en una variable -> alpicamos fig.show()
fig = go.Figure(data=[go.Table(header=dict(values=encabezado),
cells=dict(values=valores))
])
fig.show()
Podemos arreglar
fig = go.Figure(data=[go.Table(
#Encabezado
header=dict(values=encabezado,
line_color='red', #Color borde: cambiar rojo
fill_color='lightskyblue', #Color fondo
align='left'), #Alineación
#Valores
cells=dict(values=valores,
line_color='darkslategray',#Color borde
fill_color='lightcyan', #Color rojo
align='left')) #Alineación
])
#Una vez creado el fig podemos editar su tamaño
fig.update_layout(width=300, height=300)
fig.show()
Para modificar el formato de los datos, ejemplo número de decimales, podemos usar format
encabezado = ['A Scores', 'B Scores', 'C Scores']
valores = [[100, 90, 80, 90], [95, 85, 75, 95], [95.12345, 85.12345, 75.12345, 95.12345]]
fig = go.Figure(data=[go.Table(
#Encabezado
header=dict(values=encabezado,
line_color='darkslategray', #Color borde: cambiar rojo
fill_color='lightskyblue', #Color fondo
align='left'), #Alineación
#Valores
cells=dict(values=valores,
line_color='darkslategray',#Color borde
fill_color='lightcyan', #Color rojo
align='left', #Alineación
format = [None, ".1f", ".2f"])) #Formato: en una lista va según el número de columnas
])
#Una vez creado el fig podemos editar su tamaño
fig.update_layout(width=400, height=300)
fig.show()
3. Gráficos de líneas¶
Para este ejemplo vamos a usar la librería plotly.express. Dentro de esta tenemos el DataFrame gapminder datos de expectativa de vida, población, PIB por país.
#Importamos la librería
import plotly.express as px
#Usamos un subconjunto de los datos, seleccionamos América
df = px.data.gapminder().query("continent=='Americas'")
df.head()
| country | continent | year | lifeExp | pop | gdpPercap | iso_alpha | iso_num | |
|---|---|---|---|---|---|---|---|---|
| 48 | Argentina | Americas | 1952 | 62.485 | 17876956 | 5911.315053 | ARG | 32 |
| 49 | Argentina | Americas | 1957 | 64.399 | 19610538 | 6856.856212 | ARG | 32 |
| 50 | Argentina | Americas | 1962 | 65.142 | 21283783 | 7133.166023 | ARG | 32 |
| 51 | Argentina | Americas | 1967 | 65.634 | 22934225 | 8052.953021 | ARG | 32 |
| 52 | Argentina | Americas | 1972 | 67.065 | 24779799 | 9443.038526 | ARG | 32 |
fig = px.line(df, x="year", y="lifeExp", color='country')
fig.show()
df_sur = df[(df.country=="Argentina" )| (df.country=="Chile") | (df.country=="Uruguay")]
fig = px.line(df_sur, x="year", y="gdpPercap", color='country')
fig.show()
Usamos plotly.express cuando hacemos un ejercicio sencillo. Para comenzar a ejemplos más genéricos o en algunos casos, más complejos, vamos a usar go.Scatter
Como primer ejemplo, vamos a usar una función de los DataFrame llamada pivot_table que nos va a permitir modificar nuestra serie del tipo [Fecha, PIB, Pais] a [Fecha, PIB, Argentina, Chile, Uruguay].
df.head()
| country | continent | year | lifeExp | pop | gdpPercap | iso_alpha | iso_num | |
|---|---|---|---|---|---|---|---|---|
| 48 | Argentina | Americas | 1952 | 62.485 | 17876956 | 5911.315053 | ARG | 32 |
| 49 | Argentina | Americas | 1957 | 64.399 | 19610538 | 6856.856212 | ARG | 32 |
| 50 | Argentina | Americas | 1962 | 65.142 | 21283783 | 7133.166023 | ARG | 32 |
| 51 | Argentina | Americas | 1967 | 65.634 | 22934225 | 8052.953021 | ARG | 32 |
| 52 | Argentina | Americas | 1972 | 67.065 | 24779799 | 9443.038526 | ARG | 32 |
import pandas as pd
df_sur2 = pd.pivot_table(df_sur, values=["gdpPercap"], index=["year"], columns="country" )
df_sur2.head()
| gdpPercap | |||
|---|---|---|---|
| country | Argentina | Chile | Uruguay |
| year | |||
| 1952 | 5911.315053 | 3939.978789 | 5716.766744 |
| 1957 | 6856.856212 | 4315.622723 | 6150.772969 |
| 1962 | 7133.166023 | 4519.094331 | 5603.357717 |
| 1967 | 8052.953021 | 5106.654313 | 5444.619620 |
| 1972 | 9443.038526 | 5494.024437 | 5703.408898 |
#Importamos la librería
import plotly.graph_objects as go
#Creamos figura
fig = go.Figure()
#Primer plot
#go.Scatter(x=variable_x, y=variable_y)
fig.add_trace(go.Scatter(x=df_sur2.index, y=df_sur2.gdpPercap.Argentina,
mode='lines',
name='Argentina'))
#Segundo plot
fig.add_trace(go.Scatter(x=df_sur2.index, y=df_sur2.gdpPercap.Chile,
mode='lines+markers',
name='Chile'))
# #Tercer plot
fig.add_trace(go.Scatter(x=df_sur2.index, y=df_sur2.gdpPercap.Uruguay,
mode='markers', name='Uruguay'))
fig.show()
4. Gráfico de puntos (scatter)¶
Para un gráfico simple podemos volver a usar plotly.express
#Definimos el tipo gráfico
fig = px.scatter(df_sur, x="gdpPercap", y="lifeExp", color = "country")
fig.show()
Podemos agregar una tercera dimensión, representada en el tamaño de la burbuja. Para esto usamos el argumento size y podemos transformlo en un gráfico de burbujas.
#Definimos el tipo gráfico
fig = px.scatter(df_sur, x="gdpPercap", y="lifeExp", color = "country", size="pop")
fig.show()
Otro ejemplo es agregar una escala de colores para resaltar una categoría
import plotly.graph_objects as go
import numpy as np
df_chile = df[(df.country=="Chile")]
fig = go.Figure(data=go.Scatter(
x = df_chile.gdpPercap,
y = df_chile.lifeExp,
mode='markers',
marker=dict(
size=16,
color=df_chile.lifeExp, #set color equal to a variable
colorscale='Viridis', # one of plotly colorscales
showscale=True
)
))
fig.show()
5. Gráfico de barras¶
fig = px.bar(df_chile, x='year', y='pop')
fig.show()
df_total = px.data.gapminder()
df_2007 = df_total[df_total.year==2007]
df_2007.head()
| country | continent | year | lifeExp | pop | gdpPercap | iso_alpha | iso_num | |
|---|---|---|---|---|---|---|---|---|
| 11 | Afghanistan | Asia | 2007 | 43.828 | 31889923 | 974.580338 | AFG | 4 |
| 23 | Albania | Europe | 2007 | 76.423 | 3600523 | 5937.029526 | ALB | 8 |
| 35 | Algeria | Africa | 2007 | 72.301 | 33333216 | 6223.367465 | DZA | 12 |
| 47 | Angola | Africa | 2007 | 42.731 | 12420476 | 4797.231267 | AGO | 24 |
| 59 | Argentina | Americas | 2007 | 75.320 | 40301927 | 12779.379640 | ARG | 32 |
fig = px.bar(df_2007, x="continent", y="pop", title="Wide-Form Input")
fig.show()
6. Gráfico de torta¶
df.loc[df['pop'] < 8.e6, 'country'] = 'Other countries' # Represent only large countries
fig = px.pie(df, values='pop', names='country', title='Población en América')
fig.show()
7. Animación¶
df.head()
| country | continent | year | lifeExp | pop | gdpPercap | iso_alpha | iso_num | |
|---|---|---|---|---|---|---|---|---|
| 48 | Argentina | Americas | 1952 | 62.485 | 17876956 | 5911.315053 | ARG | 32 |
| 49 | Argentina | Americas | 1957 | 64.399 | 19610538 | 6856.856212 | ARG | 32 |
| 50 | Argentina | Americas | 1962 | 65.142 | 21283783 | 7133.166023 | ARG | 32 |
| 51 | Argentina | Americas | 1967 | 65.634 | 22934225 | 8052.953021 | ARG | 32 |
| 52 | Argentina | Americas | 1972 | 67.065 | 24779799 | 9443.038526 | ARG | 32 |
import plotly.express as px
df = px.data.gapminder()
fig = px.scatter(df, x="gdpPercap", y="lifeExp",
animation_frame="year",
animation_group="country",
size="pop",
color="continent",
hover_name="country",
facet_col="continent",
log_x=True, size_max=45, range_x=[100,100000], range_y=[25,90]
)
fig.show()
fig = px.bar(df, x="continent", y="pop",
color="continent",
animation_frame="year",
animation_group="country",
range_y=[0,4000000000])
fig.show()
8. Mapa de calor¶
df = px.data.gapminder().query("continent=='Americas'")
df.head()
| country | continent | year | lifeExp | pop | gdpPercap | iso_alpha | iso_num | |
|---|---|---|---|---|---|---|---|---|
| 48 | Argentina | Americas | 1952 | 62.485 | 17876956 | 5911.315053 | ARG | 32 |
| 49 | Argentina | Americas | 1957 | 64.399 | 19610538 | 6856.856212 | ARG | 32 |
| 50 | Argentina | Americas | 1962 | 65.142 | 21283783 | 7133.166023 | ARG | 32 |
| 51 | Argentina | Americas | 1967 | 65.634 | 22934225 | 8052.953021 | ARG | 32 |
| 52 | Argentina | Americas | 1972 | 67.065 | 24779799 | 9443.038526 | ARG | 32 |
fig = go.Figure(data=go.Heatmap(
z=df.lifeExp,
x=df.year,
y=df.country,
colorscale='Viridis'
))
fig.update_layout(
title='Expectativa de vida',
xaxis_nticks=13)
fig.update_layout(width=750, height=750)
fig.show()
9. sunburst charts¶
import plotly.express as px
df = px.data.gapminder().query("year == 2007")
fig = px.sunburst(df, path=['continent', 'country'], values='pop', color='lifeExp',
hover_data=['iso_alpha'])
fig.show()
10. Treemap¶
df.head()
| country | continent | year | lifeExp | pop | gdpPercap | iso_alpha | iso_num | |
|---|---|---|---|---|---|---|---|---|
| 11 | Afghanistan | Asia | 2007 | 43.828 | 31889923 | 974.580338 | AFG | 4 |
| 23 | Albania | Europe | 2007 | 76.423 | 3600523 | 5937.029526 | ALB | 8 |
| 35 | Algeria | Africa | 2007 | 72.301 | 33333216 | 6223.367465 | DZA | 12 |
| 47 | Angola | Africa | 2007 | 42.731 | 12420476 | 4797.231267 | AGO | 24 |
| 59 | Argentina | Americas | 2007 | 75.320 | 40301927 | 12779.379640 | ARG | 32 |
import plotly.express as px
import numpy as np
df = px.data.gapminder().query("year == 2007")
fig = px.treemap(df, path=[px.Constant('world'), 'continent', 'country'], values='pop',
hover_data=['iso_alpha'])
fig.show()
11. Histograma¶
import plotly.express as px
df = px.data.tips()
fig = px.histogram(df, x="total_bill", y="tip", color="sex", marginal="rug", hover_data=df.columns)
fig.show()
12. box plots¶
import plotly.express as px
df = px.data.tips()
fig = px.box(df, x="day", y="total_bill", color="smoker", notched=True)
fig.show()
Actividad¶
Instrucciones:
Cada pregunta la debe responder en una celda diferente (en total 4 celdas de código).
Antes de cada celda de código debe ir un
markdownque muestre la pregunta que está respondiendo.En la celda de código debe agregar un breve comentario de qué está haciendo.
Revisar las bases y ver como vienen. Limpiar (en excel) para que sea sencillo importar los datos. Por ejemplo, en la base de EMPLEO las primeras 5 filas son celdas vacías o título de la hoja. Eso se puede borrar. Las columnas “C”, “E” y otras son columnas en blanco, eliminar para que no queden a la hora de importar. La fila 7 tiene un subtítulo “en miles” que no aporta, también se puede eliminar. La idea es que las bases queden sólo con las filas y columnas que va a importar a python.
Utilizando pandas importar las 4 bases, llamar: DF_IMACEC, DF_EMP, DF_IMP, DF_EXP. Limpiar para que se puedan trabajar (cambiar los nombres de variables, chequear el tipo de datos, revisar en qué fecha parten).
Crear un DataFrame que tenga la variación porcentual anual de personas para las categorías independientes (total) y asalariados (total).
Usando el DataFrame del IMACEC, transponer para que las fechas queden en las filas y las categorías como columnas. Para esto puede usar la función de pandas
pivot_table.Al DF del punto 1), agregar la variación porcentual anual del
imacecdel punto 2), usando uninner join.Utilizando
plotly, crear unsubplotque contenga:Gráfico con la variación anual de independientes, asalariados e IMACEC. Debe usar líneas, markes o dash para diferenciar las tres líneas.
Usando los DataFrame de exportaciones (EXP) e importaciones (IMP), crear un gráfico de
scatterque tenga el total de exportaciones en el eje horizontal y el total de importaciones (CIF) en el vertical. Agregue al gráfico una línea de 45°.Dentro de las exportaciones seleccione: total exportaciones, minería, agropecuario-silvícola y pesquero, industriales. Utilizando la primera fecha (enero-2009) como base 100, crear un mapa de calor que en el eje horizontal tenga las fechas y en el vertical las 4 categorías. Cambie la escala de colores (no utilizar el por defecto).
Cada gráfico debe tener un subtítulo, nombre de ejes y una leyenda -según corresponda-. hint: la clave es que ordene bien los datos antes del gráfico. Luego piense bien a qué debe llegar.
Clase 17: Introducción al análisis de texto (text mining)¶
En esta clase veremos una introducción al procesamiento de texto. Para esto utilizaremos un discurso presidencial y veremos como depurar este texto, de manera que podamos extraer información relevante.
Vamos a
Examinar el texto
Depurar:
Remover símbolos
Remover números
Mayúscula-minúscula
Espacios en blanco
Tíldes
Tokenizar
Frecuencias de palabras
Stopwords
Wordclouds
Stemming
N-gramas
1. Introducción¶
En el mundo moderno tenemos muchas fuentes de información, la tarea es cómo la recopilamos, procesamos y analizamos.
Por ejemplo, las frases, textos, libros, comentarios en redes sociales, son una amplia gama de fuentes de información. El text mining es “obtener información interesante y no trivial de textos o información no estructurada”.
Ejemplos de información que podemos recopilar y procesar:
Noticias de diarios electrónicos
Libros
Twitter
etc.
Para efectos de esta clase, veremos la librería nltk (Natural Language Toolkit), que proporciona una potente herramienta de manejo de texto.
# Tratamiento de datos
# ==============================================================================
import numpy as np
import pandas as pd
import string
import re
import nltk
# nltk.download('punkt')
# import nltk.corpus
# from nltk.tokenize import word_tokenize
Vamos a importar un archivo .txt
#Discurso 1
# discurso1 = open('C:\\Users\\ordon\\Dropbox\\Computational_Economics\\Intro_python\\Data_text_proc\\discurso1.txt', 'r')
discurso1 = open('/home/felix/Dropbox/Computational_Economics/Intro_python/Data_text_proc/discurso1.txt', 'r', encoding="latin-1")
discurso1 = discurso1.read()
discurso1
'S.E. la Presidenta de la República, Michelle Bachelet, asiste al lanzamiento de la campaña \x93Chile necesita más médicos y especialistas. Incorpórate al Sistema Público de Salud\x94\nAmigas y amigos:\n\nQué duda cabe, la verdad, como señala esta campaña del Ministerio de Salud, que \x93Chile necesita más Médicos y Especialistas\x94 en el sector público. Y es una necesidad de nuestra sociedad, y estamos dando pasos concretos para poder satisfacer esta necesidad.\n\nY uno de los grandes objetivos que tenemos como Gobierno es, justamente, mejorar la atención de salud que recibe nuestra población.\n\nY una de nuestras preocupaciones centrales es justamente fortalecer y asegurar la capacidad del Estado para responder de manera más rápida y más integral a las necesidades de millones de nuestros compatriotas que utilizan la red pública de consultorios, hospitales, centros de salud familiar y los servicios de urgencia. \n\nLa calidad de vida en nuestro país depende fuertemente de la capacidad que tengamos para, obviamente, prevenir y para asegurar, yo diría, la dignidad y el tratamiento oportuno de las enfermedades que siempre son un duro golpe para las personas y para las familias. \n\nY en este proceso, el rol de los y las profesionales de la salud es fundamental. Para enfrentar las carencias que vive nuestro sistema de salud en este ámbito, como Gobierno pusimos en marcha, desde su inicio, el Plan de Ingreso, Formación y Retención de Médicos Especialistas.\nEste Plan nos permitirá sumar, durante estos cuatro años, mil 100 médicos a la Atención Primaria de Salud y formar 4 mil especialistas, médicos y odontólogos. \n\nY ya hemos obtenido algunos avances importantes en este sentido. Este año, gracias a la ampliación en 370 cupos adicionales cada año para la Etapa de Destinación y Formación, tanto rural como urbana, pudimos contar con 538 nuevos médicos en la Atención Primaria. \n\nY para mí fue bien interesante, doctor Concha, que cuando fui a Puyehue, de los tres médicos que estaban en el CESFAM, dos eran justamente de estos médicos que habían salido con cupos adicionales para la atención primaria. \n\nEs decir, los que corresponden a la ampliación generada por este Gobierno, más los cupos que tenía anteriormente este programa que -los que ya tenemos algunos añitos- conocemos como médicos generales de zona, y que en julio de este año se celebró el aniversario número 60.\n\nLa verdad, yo creo que se trata de una experiencia, desde mi punto de vista, inigualable en la formación de un o una joven profesional de la medicina. \n\nLa tarea de los antiguos médicos generales de zona (o en Etapa de Destinación y Formación) en esas comunidades, como las veíamos en el video, donde hay que llegar en lancha, donde en general las vías de comunicación son escasas -bueno, no muy lejos de aquí, yo me acuerdo, conversando con algún médico general de zona, siendo la epidemióloga del Servicio de Salud Occidente, tenía que ir en Curacaví, pero tenía que subir a caballo a veces a ver un paciente que vivía en algún lado. O sea, que trae un poquito de aventura, trae un poquito de aventura, pero también trae un trabajo intenso, arduo, pero que también es, yo diría, algo que genera una experiencia extraordinaria-, y en general son lugares donde las vías de comunicación muchas veces son escasas, y creo que es un valor que trasciende mucho más allá del tiempo que dura su destinación. \n\nCuando recorro el país, veo el trabajo de los médicos en las localidades del sur, del norte, el cariño que le tienen los vecinos y vecinas; escucho también los recuerdos y recibo los saludos para antiguos médicos generales de zona que con el tiempo han tomado otros rumbos. Estuvimos inaugurando en Paine, me parece que fue, el CESFAM Miguel Ángel Solar, y yo pensé que era el que yo conocía, el que había sido presidente de la FEUC, pero no, era su papá, que había partido ahí, se había especializado, había estado en Estados Unidos y después volvió ahí, hasta que falleció, y trabajó en esa misma localidad. La gente lo recordaba con mucho cariño y era muy emocionante ver los videos de los pacientes que había tenido. \n\nY con la ampliación de cupos en la Etapa de Destinación y Formación, al año 2017 se habrán agregado mil 100 nuevos médicos en la Atención Primaria y en abril de 2018 esta cifra va a llegar a mil 480.\n\nEntonces, vamos a pasar de una situación en la que existía un médico cada 4 mil 300 habitantes -cuando llegamos al gobierno, era la situación que nos encontramos; un médico cada 4 mil 300, a comienzos del 2014- a otra donde habrá un médico por cada 2 mil 800 habitantes, es decir, casi el doble. Todavía nos va a faltar un poquito para lo que son los estándares de la OECD, que son alrededor de 2 mil 100 o 2 mil 200 médicos por ese número de habitantes. Entonces. Esto, obviamente, el llegar a bajar de 4 mil 300 a 2 mil 800 habitantes por médico, creo que nos acerca a los estándares de los países desarrollados. \n\nAdemás, y aquí también aprovecho de agradecer el trabajo que ha hecho el Ministerio con las universidades, con la Asociación de Facultades de Medicina de Chile, con la Asociación Chilena de Enseñanza de Odontología, con el Colegio Médico y con el Colegio de Cirujanos Dentistas, se logró ampliar en un 40% los cupos disponibles para la formación de especialistas.\n\n¡40%! Incluso algunas universidades llegaron a un 100% en la ampliación de sus cupos, y creo que es una tremenda noticia para el avance de la salud en nuestro país.\n\nY éste es un ámbito en el que vamos a continuar poniendo los máximos esfuerzos, ya que existe un importante déficit de especialistas en nuestro país (se estima que son alrededor de 3 mil 800), que afecta directamente, por cierto, la calidad de la atención que reciben los pacientes del sistema público de salud.\n\nLos y las jóvenes egresados de la carrera de medicina tienen mucho interés de participar en estos programas y aproximadamente un 60% de ellos postula a las becas de especialización.\n\nPero queremos que sean todavía más y esperamos que en los próximos años esta cifra llegue al 80%. \n\nAsí, tanto a través de la Ampliación de la Etapa de Destinación y Formación como mediante el aumento de cupos de especialización, iremos disminuyendo las carencias que afectan a la atención pública de salud.\n\nPero, al mismo tiempo, nos permitirá entregar a más profesionales la posibilidad de vivir esta experiencia única, de valor incomparable, que es ejercer el objetivo social de la medicina, llegar a lugares apartados de nuestra patria, conocer realidades diversas, también.\n\nE integrarse a la red más compleja y amplia de atención médica como es el sistema público de salud, donde van a poder formarse de manera continúa a lo largo de su carrera profesional y de aprender de los y las mejores profesionales.\n\nPorque, tal como dice la campaña, \x93Chile necesita más médicos y especialistas\x94, los médicos y especialistas necesitan conocer y valorar las oportunidades que ofrece el Sistema Público de Salud.\n\nPor eso que esta campaña de difusión llegará a todas las facultades de medicina de nuestro país, donde, estoy segura, hay una enorme cantidad de vocaciones de servicio público que esperan aportar al desarrollo de nuestra patria y a la calidad de vida de nuestros compatriotas.\n\nUstedes que están acá en un hospital público, están ejerciendo esto que es tan importante. Queremos motivar a muchos jóvenes más para que la salud pública que ellos consideren seriamente. Y estoy segura que van a sentir todas las situaciones que vivimos los médicos, pero también toda aquella experiencia, de verdad, extraordinaria que significa estar trabajando para la gente. \n\nMuchas gracias.'
Examinar texto¶
discurso1[0:1000]
'S.E. la Presidenta de la República, Michelle Bachelet, asiste al lanzamiento de la campaña \x93Chile necesita más médicos y especialistas. Incorpórate al Sistema Público de Salud\x94\nAmigas y amigos:\n\nQué duda cabe, la verdad, como señala esta campaña del Ministerio de Salud, que \x93Chile necesita más Médicos y Especialistas\x94 en el sector público. Y es una necesidad de nuestra sociedad, y estamos dando pasos concretos para poder satisfacer esta necesidad.\n\nY uno de los grandes objetivos que tenemos como Gobierno es, justamente, mejorar la atención de salud que recibe nuestra población.\n\nY una de nuestras preocupaciones centrales es justamente fortalecer y asegurar la capacidad del Estado para responder de manera más rápida y más integral a las necesidades de millones de nuestros compatriotas que utilizan la red pública de consultorios, hospitales, centros de salud familiar y los servicios de urgencia. \n\nLa calidad de vida en nuestro país depende fuertemente de la capacidad que tengamos para, o'
2. Depurar¶
El proceso de depurar implica remover o cambiar elementos que no son palabras y que para efectos del análisis del texto puedan ser irrelevantes.
Vamos a:
Remover símbolos: Los textos pueden venir con variados símbolos como “,+,,<,@, entre otros.
Remover números: hay que evaluar si los números van a ser relevantes a la hora del texto que queremos analizar. En caso que no lo sean, los vamos a quitar.
Llevar a minúscula: Hola y hola, para efectos del análisis de texto son equivalentes. Por eso llevamos todo a minúsculas.
Eliminar espacios en blanco innecesarios: vamos a borrar cuando hay más de un espacio.
Eliminar tildes: para el análisis de texto podemos eliminar las tildes, para que palabras como analisis y análisis sean equivalentes.
Borrar saltos de línea.
Remover Símbolos¶
import re
regex = '[\\!\\“\\”\\"\\#\\$\\%\\&\\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^_\\`\\{\\|\\}\\~]'
nuevo_discurso = re.sub(regex, ' ', discurso1)
print(nuevo_discurso[0:2000])
S E la Presidenta de la República Michelle Bachelet asiste al lanzamiento de la campaña Chile necesita más médicos y especialistas Incorpórate al Sistema Público de Salud
Amigas y amigos
Qué duda cabe la verdad como señala esta campaña del Ministerio de Salud que Chile necesita más Médicos y Especialistas en el sector público Y es una necesidad de nuestra sociedad y estamos dando pasos concretos para poder satisfacer esta necesidad
Y uno de los grandes objetivos que tenemos como Gobierno es justamente mejorar la atención de salud que recibe nuestra población
Y una de nuestras preocupaciones centrales es justamente fortalecer y asegurar la capacidad del Estado para responder de manera más rápida y más integral a las necesidades de millones de nuestros compatriotas que utilizan la red pública de consultorios hospitales centros de salud familiar y los servicios de urgencia
La calidad de vida en nuestro país depende fuertemente de la capacidad que tengamos para obviamente prevenir y para asegurar yo diría la dignidad y el tratamiento oportuno de las enfermedades que siempre son un duro golpe para las personas y para las familias
Y en este proceso el rol de los y las profesionales de la salud es fundamental Para enfrentar las carencias que vive nuestro sistema de salud en este ámbito como Gobierno pusimos en marcha desde su inicio el Plan de Ingreso Formación y Retención de Médicos Especialistas
Este Plan nos permitirá sumar durante estos cuatro años mil 100 médicos a la Atención Primaria de Salud y formar 4 mil especialistas médicos y odontólogos
Y ya hemos obtenido algunos avances importantes en este sentido Este año gracias a la ampliación en 370 cupos adicionales cada año para la Etapa de Destinación y Formación tanto rural como urbana pudimos contar con 538 nuevos médicos en la Atención Primaria
Y para mí fue bien interesante doctor Concha que cuando fui a Puyehue de los tres médicos que estaban en el CESFAM d
Remover números¶
nuevo_discurso = re.sub('\d+', ' ', nuevo_discurso)
print(nuevo_discurso[0:2000])
S E la Presidenta de la República Michelle Bachelet asiste al lanzamiento de la campaña Chile necesita más médicos y especialistas Incorpórate al Sistema Público de Salud
Amigas y amigos
Qué duda cabe la verdad como señala esta campaña del Ministerio de Salud que Chile necesita más Médicos y Especialistas en el sector público Y es una necesidad de nuestra sociedad y estamos dando pasos concretos para poder satisfacer esta necesidad
Y uno de los grandes objetivos que tenemos como Gobierno es justamente mejorar la atención de salud que recibe nuestra población
Y una de nuestras preocupaciones centrales es justamente fortalecer y asegurar la capacidad del Estado para responder de manera más rápida y más integral a las necesidades de millones de nuestros compatriotas que utilizan la red pública de consultorios hospitales centros de salud familiar y los servicios de urgencia
La calidad de vida en nuestro país depende fuertemente de la capacidad que tengamos para obviamente prevenir y para asegurar yo diría la dignidad y el tratamiento oportuno de las enfermedades que siempre son un duro golpe para las personas y para las familias
Y en este proceso el rol de los y las profesionales de la salud es fundamental Para enfrentar las carencias que vive nuestro sistema de salud en este ámbito como Gobierno pusimos en marcha desde su inicio el Plan de Ingreso Formación y Retención de Médicos Especialistas
Este Plan nos permitirá sumar durante estos cuatro años mil médicos a la Atención Primaria de Salud y formar mil especialistas médicos y odontólogos
Y ya hemos obtenido algunos avances importantes en este sentido Este año gracias a la ampliación en cupos adicionales cada año para la Etapa de Destinación y Formación tanto rural como urbana pudimos contar con nuevos médicos en la Atención Primaria
Y para mí fue bien interesante doctor Concha que cuando fui a Puyehue de los tres médicos que estaban en el CESFAM dos era
Convertir a minúscula¶
nuevo_discurso = nuevo_discurso.lower()
print(nuevo_discurso[0:100])
s e la presidenta de la república michelle bachelet asiste al lanzamiento de la campaña chile ne
Eliminar espacios en blanco innecesarios¶
nuevo_discurso = re.sub("\\s+", ' ', nuevo_discurso)
print(nuevo_discurso[0:100])
s e la presidenta de la república michelle bachelet asiste al lanzamiento de la campaña chile neces
Eliminar tildes y líneas en blanco¶
Eliminar diacríticos: tíldes y símbolos como ¨, ^, …
NFC: https://docs.python.org/3/library/unicodedata.html#unicodedata.normalize
from unicodedata import normalize
# -> NFD y eliminar diacríticos
nuevo_discurso = re.sub(
r"([^n\u0300-\u036f]|n(?!\u0303(?![\u0300-\u036f])))[\u0300-\u036f]+", r"\1",
normalize( "NFD", nuevo_discurso), 0, re.I
)
# -> NFC
nuevo_discurso = normalize( 'NFC', nuevo_discurso)
print(nuevo_discurso[0:200])
s e la presidenta de la republica michelle bachelet asiste al lanzamiento de la campaña chile necesita mas medicos y especialistas incorporate al sistema publico de salud amigas y amigos que duda ca
3. Tokenizar¶
Tokenizar significa dividir el texto en una unidad más pequeña, donde cada una de estas unidades va a ser un token.
Por ejemplo, podemos tokenizar texto anterior en oraciones o en palabras:
Oraciones:
token 1 = Tokenizar significa dividir el texto en una unidad más pequeña
token 2 = donde cada una de estas unidades va a ser un
token
Palabras:
token 1 = Tokenizar
token 2 = significa
token 3 = dividir
…
En nuestro ejemplo vamos a tokenizar en base a palabras.
from nltk.tokenize import word_tokenize
token = word_tokenize(nuevo_discurso)
print(token[0:10])
['s', 'e', 'la', 'presidenta', 'de', 'la', 'republica', 'michelle', 'bachelet', 'asiste']
4. Frecuencia de palabras¶
Uno de los primeros análisis que se puede realizar a partir de un texto, es la frecuencia por palabra, es decir cuántas veces se encuentra cada palabra dentro del texto.
from nltk.probability import FreqDist
fdist = FreqDist(token)
fdist
FreqDist({'de': 100, 'que': 62, 'y': 50, 'la': 48, 'en': 35, 'a': 31, 'el': 26, 'los': 25, 'las': 18, 'medicos': 17, ...})
# To find the frequency of top 10 words
fdist1 = fdist.most_common(10)
fdist1
[('de', 100),
('que', 62),
('y', 50),
('la', 48),
('en', 35),
('a', 31),
('el', 26),
('los', 25),
('las', 18),
('medicos', 17)]
5. Stopwords¶
En el ejemplo anterior vemos que las palabras más frecuentes son “de”, “que”, “y”, etc. Palabras que no aportan al análisis del texto, sino que son conectores, prepocisiones. Estas palabras son llamadas stopwords.
Para cada idioma existe un listado de stopwords y, dependiendo del contexto, se pueden ir modificando.
# nltk.download('stopwords')
from nltk.corpus import stopwords
stop_words = list(stopwords.words('spanish'))
print(stop_words[0:10])
['de', 'la', 'que', 'el', 'en', 'y', 'a', 'los', 'del', 'se']
token_sw = [x for x in token if x not in stop_words]
print(token_sw[0:10])
['s', 'presidenta', 'republica', 'michelle', 'bachelet', 'asiste', 'lanzamiento', 'campaña', '\x93chile', 'necesita']
fdist = FreqDist(token_sw)
fdist1 = fdist.most_common(10)
fdist1
[('medicos', 17),
('salud', 13),
('mil', 12),
('mas', 11),
('atencion', 8),
('publico', 7),
('formacion', 7),
('cupos', 7),
('especialistas', 6),
('medico', 6)]
6. Wordclouds¶
Una de las visualizaciones clásicas del análisis de texto, es una representación visual de la frecuencia de palabas mediante una nube de palabras (wordclouds).
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
import matplotlib.pyplot as plt
comment_words = ''
for i in range(len(token_sw)):
comment_words += " ".join(token_sw)+" "
wordcloud = WordCloud().generate(comment_words)
plt.figure(figsize = (8, 8), facecolor = None)
plt.imshow(wordcloud)
plt.axis("off")
plt.tight_layout(pad = 0)
plt.show()
wordcloud = WordCloud(max_font_size=50, max_words=100, background_color="white").generate(comment_words)
plt.figure(figsize = (10, 10), facecolor = None)
plt.imshow(wordcloud, interpolation="bilinear")
# plt.imshow(wordcloud)
plt.axis("off")
plt.tight_layout(pad = 0)
plt.show()
7. Stemming¶
Stemming (derivado de) corresponde a una normalización de palabras llevandolas a la raíz. Por ejemplo las palabras médicos, medicas, médico, médica se pueden agrupar dentro de medic. Luego, en un procesamiento de información nos va ayudar a tener información más depurada.
Sin embargo, tenemos que tener precaución con estas reducciones de significado. Por ejemplo, un paquete podría reducir médico a medic y medicina a medicin, mientras que otro más agresivo podría llevar ambos conceptos a medic. Naturalmente, para efectos del análisis de la información los resultados pueden ser muy variados.
from nltk.stem import SnowballStemmer
stemmer = SnowballStemmer('spanish')
stemmer.stem('medico')
'medic'
token_st =[stemmer.stem(x) for x in token_sw]
token_st[0:10]
['s',
'president',
'republ',
'michell',
'bachelet',
'asist',
'lanzamient',
'campañ',
'\x93chil',
'necesit']
comment_words = ''
for i in range(len(token_st)):
comment_words += " ".join(token_st)+" "
wordcloud = WordCloud(max_font_size=50, max_words=100, background_color="white").generate(comment_words)
plt.figure(figsize = (8, 8), facecolor = None)
plt.imshow(wordcloud, interpolation="bilinear")
# plt.imshow(wordcloud)
plt.axis("off")
plt.tight_layout(pad = 0)
plt.show()
8. N-gramas¶
Podemos escribir “el computador está apagado”, pero sería incorrecto decir “apagado el está computador”. En este contexto, los N-gramas con estructuras de palabras que se suceden.
Por ejemplo:
Bi-grama: (el, computador), (computador, está)
Tri-grama: (el, computador, está), (computador, está, apagado)
Capturamos cierto significado de un conjunto de palabras.
from nltk import ngrams
sentence = 'this is a foo bar sentences and i want to ngramize it'
n = 3
n2grams = ngrams(nuevo_discurso.split(), n)
from nltk.probability import FreqDist
fdist = FreqDist(n2grams)
fdist
FreqDist({('sistema', 'publico', 'de'): 4, ('la', 'atencion', 'primaria'): 4, ('etapa', 'de', 'destinacion'): 4, ('de', 'destinacion', 'y'): 4, ('destinacion', 'y', 'formacion'): 4, ('\x93chile', 'necesita', 'mas'): 3, ('necesita', 'mas', 'medicos'): 3, ('mas', 'medicos', 'y'): 3, ('la', 'calidad', 'de'): 3, ('en', 'nuestro', 'pais'): 3, ...})
fdist1 = fdist.most_common(10)
x=[]
y=[]
for i in fdist1:
x.append(str(i[0]))
y.append(i[1])
print(x[0])
('sistema', 'publico', 'de')
import plotly.graph_objects as go
fig = go.Figure(go.Bar(
x=y,
y=x,
orientation='h'))
fig.update_layout(width=700, height=500)
fig.show()
Clase 18: Introducción al uso de clases¶
En esta sesión veremos el uso de clases y programación orientada a objetos.
Repaso
Introducción a las clases
Definir una clase
Llamar funciones dentro de una clase
Actualizar parámetros
Ejercicio
1. Repaso¶
Revisamos qué es
Python, por qué es tan popular y cómo instalamosAnacondayJupyter.Aprendimos qué es una
librería, cómo se instala y cómo utilizar diferentes módulos.Revisamos como crear
variablesy los diferentestypes(tipos) que podemos usar.Vimos la diferentecia entre
arraysylistas.Creamos
loopspara obtener iteraciones, cómo acceder a los elementos de una lista/array utilizando loops.Aprendimos el uso de condicionales:
if/else.Creamos
funciones(def), la flexibilidad de éstas y vimos qué es el input y output.Aprendimos qué es un
diccionario, qué es una llave (key) y valor (value). Cómo nos sirve para ordenar nuestra información y cómo podemos vincularlo con loops y condicionales.Revisamos librerías de gŕaficos:
MatplotlibyPlotly.Trabajamos con datos estructurados mediante la librería
Pandas:Importar datos
Limpiar información
Datos de texto, numéricos y fechas
Crear un DataFrame
Manipular el DataFrame
Usando pandas aprendimos a manejar bases de
datos relacionales: tipo SQL.Nos introdujimos al mundo del
análisis de texto(text mining).
Librerías que hemos ocupados:
Numpy
Pandas
Matplotlib
Plotly
nltk
re
2. Introducción¶
La programación orientada a objectos es un enfoque de desarrollo de sistemas centrado en objetos y como interactúan. Por ejemplo, pensemos en los elementos de alrededor, un computador, celular, escritorio, cama, etc. ¿Cómo interactúan? Me conecto al computador, utilizo el celular, subo una foto a instagram, etc.
En la programación vamos a tener objetos y vamos a establecer mecanismos para que estos interactúen. Los códigos se van a enfocar en establecer objetos y clases.
En este contexto, un objeto va a ser una forma específica de organizar un código y que va a estar definida, de tal forma, que va a englobar los datos y el comportamiento. Esto significa que los datos y los procesos (funciones) van a pertenecer a uno o más objetos.
Otra forma de ver los procedemientos es el paradigma procedural (procedural paradigm), que en simple es dividir el problema en en pequeñas partes (funciones) y vamos combinando los procedimientos, donde se comparte data entre procesos o mediante variables globales. Por otro lado, la programación orientada a objetos divide el problema en pequeñas partes (objetos) y el código está construido alrededor de los objetos. “Los objetos buscan representar cosas que existen en el mundo real en un sistema de cómputo”. Los objetos no comparten datos.
Las clases (class) nos permiten ordenar datos y funciones. De forma incompleta e introductoria, podemos pensar las clases como una gran función de funciones, que nos va a permitir ordenar códigos que pueden ser grandes y con gran cantidad de sub-funciones.
Cuando creamos una nueva clase (class) vamos a crear un nuevo tipo (type) de objeto. Cada clase va a tener atributos particulares a ésta y métodos para modificarla.
Existen lenguajes que funcionan exclusivamente orientados a objetos, como Java, y otros como Python que son lenguajes multipropósito que permiten trabajar con mecanismos del tipo procedural u objetos.
Veamos un ejemplo
from IPython.display import Image
import numpy as np
import scipy.io as sio
Image("Clases.png")
Image("Clases2.png")
3. Definir una clase¶
class Empresa:
#Dos cosas fundamentales: __init__() y "self"
#init(): cada clase tiene la función __init__(). Se ejecuta cada vez se llama la clase.
# su función es asignar valores a los objetos.
#self: el parámetro self permite hacer referencia dentro de una instancia de la clase,
#sean parámetros o métodos. No necesariamente se tiene que llamar self.
def __init__(self, ingresos, costos, salarios, personas):
self.ingresos = ingresos #variable única a cada instancia
self.costos = costos
self.salarios = salarios
self.personas = personas
emp1 = Empresa("100", "50", "20", "10") #Probar quitando un argumento
print("Empresa 1:", "Ingresos, costos", (emp1.ingresos, emp1.costos))
emp2 = Empresa("1000", "200", "500", "30") #Probar quitando un argumento
print("Empresa 2:", "Ingresos, costos", (emp2.ingresos, emp2.costos))
Empresa 1: Ingresos, costos ('100', '50')
Empresa 2: Ingresos, costos ('1000', '200')
4. Llamar funciones dentro de una clase¶
# llamar funciones dentro de la clase
class Empresa:
def __init__(self, ingresos, costos, salarios, personas):
self.ingresos = float(ingresos)
self.costos = float(costos)
self.salarios = float(salarios)
self.personas = float(personas)
def myfunc(self):
ingresos = str(self.ingresos)
costos = str(self.costos)
print("La Empresa tiene ingresos y costos por " + ingresos + " y " + costos + " respectivamente.")
def utilidades(self):
ingresos = self.ingresos
costos = self.costos
return ingresos-costos
def salario_pp(self):
salarios = self.salarios
personas = self.personas
return salarios/personas
def utilidades_pp(self):
utilidades = self.utilidades()
personas = self.personas
return utilidades/personas
ingresos = input('¿Cuál es el ingreso de la empresa?')
costos = input('¿Cuáles son los costos de la empresa?')
salarios = input('¿Cuál es el total de salarios?')
personas = input('¿Cuántas personas trabajan en la empresa?')
emp1 = Empresa(ingresos, costos, salarios, personas) #Probar quitando un argumento
---------------------------------------------------------------------------
StdinNotImplementedError Traceback (most recent call last)
<ipython-input-5-52e05aea364c> in <module>
29
30
---> 31 ingresos = input('¿Cuál es el ingreso de la empresa?')
32 costos = input('¿Cuáles son los costos de la empresa?')
33 salarios = input('¿Cuál es el total de salarios?')
~/miniconda3/lib/python3.9/site-packages/ipykernel/kernelbase.py in raw_input(self, prompt)
843 """
844 if not self._allow_stdin:
--> 845 raise StdinNotImplementedError(
846 "raw_input was called, but this frontend does not support input requests."
847 )
StdinNotImplementedError: raw_input was called, but this frontend does not support input requests.
emp1.myfunc()
emp1.utilidades()
emp1.salario_pp()
emp1.utilidades_pp()
La Empresa tiene ingresos y costos por 100.0 y 10.0 respectivamente.
45.0
5. Actualizar parámetros¶
class Ej_param1:
def __init__(self, α, β):
self.α = α
self.β = β
self.γ = self.α / self.β
def myfunc(self):
α, β, γ = self.α, self.β, self.γ
return α * β**γ
α = 0.3
β = 0.7
par = Ej_param1(α, β)
resultado = par.myfunc()
print(resultado)
0.2574747827902883
class Ej_param2:
def __init__(self, α=0.5, β=0.7):
self.α = α
self.β = β
self.γ = self.α / self.β
def myfunc(self):
α, β, γ = self.α, self.β, self.γ
return α * β**γ
par = Ej_param2(α = 0.3) #probar sin actualizar valores o actualizando valores
resultado = par.myfunc()
print(resultado)
0.2574747827902883
class Ej_param3:
def __init__(self, **kwargs):
#unspecified number of arguments to a function
#kwargs allows you to pass keyworded variable length of arguments to a function
self.parameters()
self.update_parameters(kwargs)
self.parameters2()
def parameters(self):
#Parámetros básicos
self.α = 0.5
self.β = 0.7
def parameters2(self):
#Parámetros compuestos
self.γ = self.α / self.β
def update_parameters(self, kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
#syntax: setattr(object, name, value)
def myfunc(self):
α, β, γ = self.α, self.β, self.γ
return α * β**γ
par = Ej_param3(α = 0.3) #probar sin actualizar valores o actualizando valores
resultado = par.myfunc()
print(resultado)
0.2574747827902883
6. Ejercicio 1¶
Supongamos que modelo de oferta y demanda:
Definir una función para la oferta y otra para la de demanda.
Graficar las curvas \(S(q)\) y \(D(q)\) para un set de \(q\in (0,16)\).
Obtener el precio y cantidad de equilibrio.
Graficar el equilibrio.
Agregar todo lo anterior en una clase.
Definir una función para la oferta y otra para la de demanda.
#1. Definir una función para la oferta y otra para la de demanda.
#Oferta
def S(q):
return (q**2)
#Demanda
def D(q):
return (q - 20)**2
Graficar las curvas \(S(q)\) y \(D(q)\) para un set de \(q\in (0,16)\).
#2. Graficar las curvas $S(q)$ y $D(q)$ para un set de $q\in (0,16)$.
#Librerías
%matplotlib inline
#Magic function: muestra los gráficos directo después de crearlos
import numpy as np
import matplotlib.pyplot as plt
#Crear vector de cantidad
q = np.linspace(0, 16, 1000)
#Graficar
plt.plot(q, S(q), label = "Oferta") #Gŕafico oferta
plt.plot(q, D(q), label = "Demanda") #Gráfico demanda
plt.title("Oferta y demanda") #Título
plt.legend() #Leyenda
plt.xlabel("Cantidad $q$") #Label eje x
plt.ylabel("Precio") #Label eje y
Text(0, 0.5, 'Precio')
Obtener el precio y cantidad de equilibrio.
El equilibrio se encuentra donde la función de oferta y demanda se intersectan: $\(S(q) = D(q)\)$
#3. Obtener el precio y cantidad de equilibrio.
#Librería: Symbolic Computation -> trabajar con problemas matemáticos simbólicamente
import sympy as sy
q = sy.Symbol('q')
print("q:", q)
eq = sy.Eq(S(q), D(q))
eq
q: q
q_sol = sy.solve(eq)
print("q_sol:", q_sol)
q_sol: [10]
p_sol = S(q_sol[0])
print("Equilibrio (q,p):", (q_sol, p_sol))
Equilibrio (q,p): ([10], 100)
Graficar el equilibrio.
#4. Graficar el equilibrio.
plt.figure(figsize= (10, 8))#create figure and reset q to be numbers
q = np.linspace(0, 16, 1000)
plt.plot(q, S(q), label = "Oferta")#plot supply, demand, and equilibrium points
plt.plot(q, D(q), label = "Demanda")
plt.plot(q_sol[0], p_sol, 'o', markersize = 14)
plt.title("Oferta y demanda")#add titles and legend
plt.legend()
plt.xlabel("Cantidad $q$")
plt.ylabel("Precio")
ax = plt.axes()#add arrow with annotation
ax.annotate('Equilibrio (10, 100)', xy=(10,100), xytext=(10, 250), arrowprops=dict(facecolor='black'))
<ipython-input-15-06f2ed6b7c24>:14: MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance. In a future version, a new instance will always be created and returned. Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.
ax = plt.axes()#add arrow with annotation
Text(10, 250, 'Equilibrio (10, 100)')
Agregar todo lo anterior en una clase.
class S_D:
def __init__(self, q, β=1):
self.q = q
self.β = β
#Oferta
def S(self):
q = self.q
β = self.β
return (q**2)
#Demanda
def D(self):
q = self.q
return (q - 20)**2
def sol(self):
β = self.β
#Cantidad
q = sy.Symbol('q')
S = self.S()
D = self.D()
#Equilibrio : oferta=demanda
eq = sy.Eq(S, D)
#Solución
q_sol = sy.solve(eq)
p_sol = β*q_sol[0]**2
return q_sol[0], p_sol
def plot(self, Q):
#Llamar del self
# q=self.q
q_sol, p_sol = self.sol()
self.q = Q
plt.figure(figsize= (10, 8))
plt.plot(Q, self.S(), label = "Oferta")#plot supply, demand, and equilibrium points
plt.plot(Q, self.D(), label = "Demanda")
plt.plot(q_sol, p_sol, 'o', markersize = 14)
plt.title("Oferta y demanda")#add titles and legend
plt.legend()
plt.xlabel("Cantidad $q$")
plt.ylabel("Precio")
ax = plt.axes()#add arrow with annotation
ax.annotate('Equilibrio' + str((q_sol, p_sol)), xy=(q_sol, p_sol), xytext=(q_sol, 250), arrowprops=dict(facecolor='black'))
plt.show()
Q = np.linspace(0.1, 16, 1000)
q = sy.Symbol('q')
sd = S_D(q, β=1)
sd.sol()
sd.plot(Q)
<ipython-input-31-2225e630ba8b>:48: MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance. In a future version, a new instance will always be created and returned. Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.
ax = plt.axes()#add arrow with annotation
7. Ejercicio 2¶
Usando el ejemplo de bases relacionales que vimos en clases, crear una clase que tenga como características las bases de nombre, edad y almuerzo.
Crear una función que según un nombre muestre la hora promedio de almuerzo.
Función que grafique el promedio de la hora de almuerzo por día.
Crear función que devuelva el data frame con las variables id, nombre, edad, día, hora y almuerzo.
Función que devuelva el DataFrame corregido, excluyendo los NaN.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
nombre = pd.read_excel("ejemplo_sql.xlsx", sheet_name='nombre', thousands=",")
edad = pd.read_excel("ejemplo_sql.xlsx", sheet_name='edad', thousands=",")
almuerzo = pd.read_excel("ejemplo_sql.xlsx", sheet_name='Almuerzo', thousands=",")
Clase 19: Scipy y computación numérica¶
En esta clase revisaremos el trabajo, la librería scipy.
Scipy¶
La librería scipy es una librería de computación científica que utiliza numpy. Nos va a permitir realizar optimización, procesos estadísticos, interpolación, procesamiento de imágenes, integración, entre otros.
Álgebra lineal¶
Para operaciones de álgebra lineal podemos ocupar el módulo linag.
#1. Determinante de una matriz
import numpy as np
from scipy import linalg
arr = np.array([[1, 2],
[3, 4]])
linalg.det(arr)
-2.0
arr = np.array([[3, 2],
[6, 4]])
linalg.det(arr)
0.0
#2. Inversa de una matriz
linalg.inv(arr)
# calcular la inversa de una matriz singular (su determinante es cero) generará un error
---------------------------------------------------------------------------
LinAlgError Traceback (most recent call last)
<ipython-input-3-317de499420c> in <module>
1 #2. Inversa de una matriz
----> 2 linalg.inv(arr)
3 # calcular la inversa de una matriz singular (su determinante es cero) generará un error
~/miniconda3/lib/python3.9/site-packages/scipy/linalg/basic.py in inv(a, overwrite_a, check_finite)
966 inv_a, info = getri(lu, piv, lwork=lwork, overwrite_lu=1)
967 if info > 0:
--> 968 raise LinAlgError("singular matrix")
969 if info < 0:
970 raise ValueError('illegal value in %d-th argument of internal '
LinAlgError: singular matrix
arr = np.array([[1, 2],
[3, 4]])
linalg.inv(arr)
array([[-2. , 1. ],
[ 1.5, -0.5]])
Optimización¶
Podemos ocupar el módulo optimize para encontrar el mínimo (máximo) de una función (escalares o multidimensional).
from scipy import optimize
import matplotlib.pyplot as plt
def f(x):
return x**2 + 10*np.sin(x)
x = np.arange(-10, 10, 0.1)
plt.plot(x, f(x))
plt.show()
Mínimo global: corresponde al valor mínimo en el dominio de la función. Mínimo local: corresponde al valor mínimo en una región particular de la curva.
En el ejemplo tenemos un mínimo local y un mínimo global. Mediante un algoritmo de scipy podemos encontrar estos valores, por ejemplo podemos usar la función fmin_bfgs (método BFGS) para encontrar el mínimo.
#Usamos el módigo optmize, la función fmin_bfgs
#La sintaxis es fmin_bfgs(función a optimizar, valor inicial)
opt = optimize.fmin_bfgs(f, 0)
print(opt)
#El resultado nos entrega:
#1) Valor de la función evaluada en el punto mínimo
#2) Número de iteraciones que se demoró en encontrar el mínimo
#3) Número de evaluaciones de la función
#4) Número de evaluaciones del gradiente
#5) Parámetro que minimiza la función
Optimization terminated successfully.
Current function value: -7.945823
Iterations: 5
Function evaluations: 12
Gradient evaluations: 6
[-1.30644012]
Por la naturaleza del método podemos quedar en el mínimo local si no partimos del “lado correcto”
optimize.fmin_bfgs(f, 3)
Optimization terminated successfully.
Current function value: 8.315586
Iterations: 6
Function evaluations: 14
Gradient evaluations: 7
array([3.83746709])
Cuando no sabemos el intervalo del mínimo global podemos ocupar un método costoso que utiliza la fuerza bruta, en que se evalúa la función en cada punto
grid = (-10, 10, 0.1)
xmin_global = optimize.brute(f, (grid,))
xmin_global
array([-1.30641113])
Podemos encontrar un mínimo local (dentro de un intervalo), usando fminbound
xmin_local = optimize.fminbound(f, 0, 10)
print(xmin_local)
3.8374671194983834
Para encontrar las raíces de una función, podemos utilizar fsolve. La raíz corresponde al punto donde \(f(x)=0\).
root = optimize.fsolve(f, 1) # our initial guess is 1
root
array([0.])
Si la función tiene más de una raíz, tenemos que cambiar el valor inicial para partir de un punto que nos lleve a la segunda (tercera…) solución
root2 = optimize.fsolve(f, -2.5)
root2
array([-2.47948183])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, f(x), 'b-', label="f(x)")
xmins = np.array([xmin_global[0], xmin_local])
ax.plot(xmins, f(xmins), 'go', label="Minima")
roots = np.array([root, root2])
ax.plot(roots, f(roots), 'kv', label="Roots")
ax.legend()
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
Text(0, 0.5, 'f(x)')
Supongamos que \(f\) tiene un poco de ruido
xdata = np.linspace(-10, 10, num=20)
ydata = f(xdata) + np.random.randn(xdata.size)
plt.plot(x, f(x), 'b-', label="f(x)")
plt.plot(xdata, ydata, color="red")
[<matplotlib.lines.Line2D at 0x7f6a1004aa00>]
La forma funcional original es $\(f(x) = x^2 + 10*sin(x)\)$
Entonces podemos generalizar mediante
Mediante curve_fit() podemos encontrar los valores de a y b.
def f2(x,a ,b):
return a*x**2 + b**np.sin(x)
#Valor inicial
guess = [2,2]
#curve_fit(f, xdata, ydata, valor inicial)
params, params_covariance = optimize.curve_fit(f2, xdata, ydata, guess)
#retorna:
#1) Valores óptimos que minimizan f(xdata) - ydata
#2) Covarianza estimada de valores óptimos
params
array([ 0.95241285, 11.53081666])
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, f(x), 'b-', label="f(x)")
ax.plot(x, f2(x, *params), 'r--', label="Curve fit result")
xmins = np.array([xmin_global[0], xmin_local])
ax.plot(xmins, f(xmins), 'go', label="Minima")
roots = np.array([root, root2])
ax.plot(roots, f(roots), 'kv', label="Roots")
ax.legend()
ax.set_xlabel('x')
ax.set_ylabel('f(x)')
Text(0, 0.5, 'f(x)')
Estadísticas y números aleatorios¶
Podemos ocupar el módulo scipy.stats tiene potentes herramientas estadísticas y probabilísticas.
Para la generación de procesos aleatorios podemos ocupar numpy.random
a = np.random.normal(size=10_000)
plt.plot(a)
[<matplotlib.lines.Line2D at 0x7f6a0ffa56a0>]
plt.hist(x=a, bins=50, alpha=0.7, rwidth=0.85);
mu, sigma = 2, 0.5
s = np.random.normal(mu, sigma, 10000)
plt.hist(x=s, bins=50, alpha=0.7, rwidth=0.85);
n, p = 10, .5
s = np.random.binomial(n, p, 10_000)
plt.plot(s)
#Resultado de tirar una moneda 10 veces, testeado 10_000 veces
[<matplotlib.lines.Line2D at 0x7f6a0f8fa4c0>]
plt.hist(x=s, bins=10, alpha=0.7, rwidth=0.85);
sum(np.random.binomial(2, 0.1, 20000) == 0)/20000
#COrremos el modelo 20_000 veces, y vemos el resultado de la probabilidad que se generen valores igual a cero
0.81165
Probability density function for norm: $\(f(x) = \frac{exp(-x^2/2)}{\sqrt{2\pi}}\)$
#Probability density function
from scipy.stats import norm
#Obtener momentos
x = np.linspace(-3, 3, 1000)
pdf = norm.pdf(x)
plt.plot(x, pdf)
[<matplotlib.lines.Line2D at 0x7f6a0e9992b0>]
cdf = norm.cdf(x)
plt.plot(x, cdf)
[<matplotlib.lines.Line2D at 0x7f6a0e971d30>]
cdf = np.linspace(0, 1, 1000)
ppf = norm.ppf(cdf)
plt.plot(ppf, cdf)
[<matplotlib.lines.Line2D at 0x7f6a0e92e910>]
Interpolación¶
Cuando tenemos datos y no conocemos su forma funcional, podemos realizar una aproximación mediante una interpolación. Esto consiste en evaluar los puntos y obtener una aproximación de la función. En simple, nos permite mediante un set de valores discretos tener una función que nos permite tener un espacio continuo
Para esto podemos ocupar el módulo interpolate
#Creamos datos experimentales: ejm similar a una función seno
x = np.linspace(0, 1, 10)
noise = (np.random.random(10)*2 - 1) * 1e-1
valores = np.sin(2 * np.pi * x) + noise
plt.plot(x, valores);
from scipy.interpolate import interp1d
#Creamos valores nuevos
val_nuevos = np.linspace(0, 1, 50)
#Interpolación lineal
linear_interp = interp1d(x, valores)
linear_results = linear_interp(val_nuevos)
#Interpolación cúbica
cubic_interp = interp1d(x, valores, kind='cubic')
cubic_results = cubic_interp(val_nuevos)
plt.plot(x, valores, 'o', ms=6, label='Valores')
plt.plot(val_nuevos, linear_results, label='linear interp')
plt.plot(val_nuevos, cubic_results, label='cubic interp')
plt.legend()
plt.show()
Actividad¶
Obtenga la inversa de una matriz a del tipo $\(a = \left[ \begin{array}{ccc} 3 & 2 & 0 \\ 1 & -1 & 0 \\ 0 & 5 & 1 \\ \end{array}\right]\)$
inv_a = linalg.inv(a)
Resuelva el sistema \(a*x = b\), donde $\(b = \left[ \begin{array}{c} 2 \\ 4 \\ -1 \\ \end{array}\right]\)$
import numpy as np
a = np.array([[3, 2, 0], [1, -1, 0], [0, 5, 1]])
b = np.array([2, 4, -1])
from scipy import linalg
x = linalg.solve(a, b)
x
array([ 2., -2., 9.])
Si compara \(x = a^{-1}*b\) usando 1) con el resultado de 2), son iguales?
inv_a @ b
array([ 2., -2., 9.])
4.
4.0
b = 10;
def f(X):
return (X[0]-1)**2 + b*(X[1]-X[0]**2)**2
# Initialize figure
import matplotlib.pyplot as plt
figRos = plt.figure(figsize=(12, 7))
axRos = figRos.gca(projection='3d')
# Evaluate function
X = np.arange(-2, 2, 0.15)
Y = np.arange(-1, 3, 0.15)
X, Y = np.meshgrid(X, Y)
Z = f([X,Y])
# Plot the surface
surf = axRos.plot_surface(X, Y, Z,
linewidth=0, antialiased=False)
axRos.set_zlim(0, 200)
figRos.colorbar(surf, shrink=0.5, aspect=10)
plt.show()
from scipy.optimize import least_squares
input = np.array([2, 2])
res = least_squares(f, input)
res
active_mask: array([0., 0.])
cost: 0.0021748096395843544
fun: array([0.06595164])
grad: array([-0.00102082, 0.01379367])
jac: array([[-0.01547836, 0.20914825]])
message: 'The maximum number of function evaluations is exceeded.'
nfev: 200
njev: 189
optimality: 0.013793670721659863
status: 0
success: False
x: array([1.25467248, 1.58466043])
Clase 20: Regresiones¶
En esta clase revisaremos los conceptos econométricos de Mínimos Cuadrados Ordinarios (OLS por sus siglas en inglés) y Modelo Autorregresivo (AR por sus siglas en inglés).
Para esto vamos a utilizar la librería statsmodels: https://www.statsmodels.org/stable/install.html
Mínimos Cuadrados Ordinarios (Ordinary Least Squares)¶
Buscamos estimar la Función de Regresión Poblacional (FRP), sin embargo esta no es observable directamente. Para esto vamos a utilizar una estimación que llamaremos la Función de Regresión Muestral (FRM):
FRP: \(Y_i = \beta_1 + \beta_2 X_i + \mu_i\)
FRM: \(Y_i = \hat{\beta}_1 + \hat{\beta}_2 X_i + \hat{\mu}_i = \hat{Y}_i - \hat{\mu}_i\), donde \(\hat{Y}_i\) es el valor estimado (media condicional) de \(Y_i\).
Entonces, en OLS vamos a minimizar el error \(\hat{\mu}_i = Y_i - \hat{Y_i}\) $\(\begin{align} \sum u_i^2 &= \sum (Y_i-\hat{Y}_i)^2 \\ &= \sum (Y_i - \hat{\beta}_1 - \hat{\beta}_2 X_i)^2 \end{align}\)$
from IPython.display import Image
Image("OLS1.png")
import pandas as pd
import numpy as np
df = pd.read_stata("/home/felix/Dropbox/Computational_Economics/Intro_python/Data_OLS_AR/Casen2020.dta");
/home/felix/miniconda3/lib/python3.9/site-packages/pandas/io/stata.py:1417: UnicodeWarning:
One or more strings in the dta file could not be decoded using utf-8, and
so the fallback encoding of latin-1 is being used. This can happen when a file
has been incorrectly encoded by Stata or some other software. You should verify
the string values returned are correct.
warnings.warn(msg, UnicodeWarning)
detalle_ingreso = df.ytrabajocor.describe()
detalle_ingreso
count 7.350900e+04
mean 5.783447e+05
std 1.264676e+06
min 4.000000e+00
25% 2.000000e+05
50% 3.681670e+05
75% 6.500000e+05
max 2.250000e+08
Name: ytrabajocor, dtype: float64
df2 = df[(df.ytrabajocor>0) & (df.ytrabajocor<10_000_000) & (df.ytrabajocor.notna())]
df2.ytrabajocor.describe()
count 7.345000e+04
mean 5.617230e+05
std 6.973099e+05
min 4.000000e+00
25% 2.000000e+05
50% 3.674275e+05
75% 6.500000e+05
max 9.850000e+06
Name: ytrabajocor, dtype: float64
plt.plot(df2.ytrabajocor, 'g')
plt.xlabel("Observación")
plt.ylabel('Ingreso del trabajo')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-5-b7adf0787577> in <module>
----> 1 plt.plot(df2.ytrabajocor, 'g')
2 plt.xlabel("Observación")
3 plt.ylabel('Ingreso del trabajo')
NameError: name 'plt' is not defined
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 8))
plt.hist(df2.ytrabajocor, 50, density=True, facecolor='g', alpha=0.75)
plt.xlim([0, 5_000_000])
plt.xlabel('Ingreso del trabajo')
plt.ylabel('Densidad')
plt.show()
y_educ_bas = df2[["ytrabajocor", "educ"]][df2.educ=="Básica incompleta"].ytrabajocor
y_educ_uni = df2[["ytrabajocor", "educ"]][df2.educ=="Profesional completo"].ytrabajocor
fig = plt.figure(figsize=(8, 8))
plt.hist(y_educ_bas, 50, density=True, facecolor='g', alpha=0.75)
plt.hist(y_educ_uni, 50, density=True, facecolor='r', alpha=0.75)
plt.xlim([0, 5_000_000])
plt.xlabel('Ingreso del trabajo')
plt.ylabel('Densidad')
plt.show()
Datos para la regresión
y = df2.ytrabajocor
X = df2.esc
X = sm.add_constant(X)
X.head()
| const | esc | |
|---|---|---|
| 0 | 1.0 | 12.0 |
| 3 | 1.0 | 15.0 |
| 4 | 1.0 | NaN |
| 5 | 1.0 | 16.0 |
| 7 | 1.0 | 15.0 |
#Hay que limpiar los NaN en variable exógena
df3 = df[(df.ytrabajocor>0) & (df.ytrabajocor<10_000_000) & (df.ytrabajocor.notna()) & (df.esc.notna())]
y = df3.ytrabajocor
X = df3.esc
X = sm.add_constant(X)
X.head()
| const | esc | |
|---|---|---|
| 0 | 1.0 | 12.0 |
| 3 | 1.0 | 15.0 |
| 5 | 1.0 | 16.0 |
| 7 | 1.0 | 15.0 |
| 11 | 1.0 | 14.0 |
y = df3.ytrabajocor
X = df3.esc
X = sm.add_constant(X)
X.head()
import statsmodels.api as sm
model = sm.OLS(y, X)
results = model.fit()
print(results.summary())
OLS Regression Results
==============================================================================
Dep. Variable: ytrabajocor R-squared: 0.183
Model: OLS Adj. R-squared: 0.183
Method: Least Squares F-statistic: 1.601e+04
Date: Mon, 26 Jul 2021 Prob (F-statistic): 0.00
Time: 22:21:34 Log-Likelihood: -1.0554e+06
No. Observations: 71466 AIC: 2.111e+06
Df Residuals: 71464 BIC: 2.111e+06
Df Model: 1
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const -3.694e+05 7751.498 -47.662 0.000 -3.85e+05 -3.54e+05
esc 7.572e+04 598.451 126.532 0.000 7.45e+04 7.69e+04
==============================================================================
Omnibus: 64620.243 Durbin-Watson: 1.630
Prob(Omnibus): 0.000 Jarque-Bera (JB): 3238679.663
Skew: 4.257 Prob(JB): 0.00
Kurtosis: 34.861 Cond. No. 43.0
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
No. Observations: número de observaciones ocupadas en la regresión.
R-squared: El \(R^2\) es la proporción de la varianza en la variable dependiente que puede ser predicha por las variables independientes. En este caso un 18% de la varianza es explicada por las variables independientes.
Adj R-squared (\(R^2\) ajustado): el \(R^2\) se ajusta para penalizar que se agreguen regresores extraños.
F-statistic (F(Z,)): Es la razón entre el error cuadrático medio del modelo y el error cuadrático medio de los residuos. Nos sirve para determinar la importancia general del modelo.
Criterios de información (AIC y BIC): nos sirven para ver el trade-off entre complejidad del modelo y bondad de ajuste de este.
Image("OLS3.png")
En las filas están las variables con las que regresionamos: constante y educación. En las columnas tenemos:
El coeficiente de las variables independientes y la constante. Acá estamos estimando los \(\beta_i\): \(Y_i = \hat{\beta}_1 + \hat{\beta}_2 X_i + \hat{\mu}_i\)
std err: error estándar asociado a los coeficientes.
t: estadístico t usado para testear la significancia de los coeficientes.
\(P>|t|\): p-value de dos colas usado para testear hipótesis nula de que el coeficiente es cero (\(\alpha=0.05\)).
[0.025 - 0.975]: intervalo de confianza de coeficiente con \(\alpha=0.05\).
#df.loc[df['column name'] condition, 'new column name'] = 'value if condition is met'
df3.loc[df3.sexo=="Hombre", "sexo2"] = 0
df3.loc[df3.sexo=="Mujer", "sexo2"] = 1
/home/felix/miniconda3/lib/python3.9/site-packages/pandas/core/indexing.py:1599: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
self.obj[key] = infer_fill_value(value)
/home/felix/miniconda3/lib/python3.9/site-packages/pandas/core/indexing.py:1720: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
self._setitem_single_column(loc, value, pi)
y = df3.ytrabajocor
X = df3[["esc", "edad", "sexo2"]]
X = sm.add_constant(X)
X.head()
| const | esc | edad | sexo2 | esc2 | |
|---|---|---|---|---|---|
| 0 | 1.0 | 12.0 | 34 | 1.0 | 144.0 |
| 3 | 1.0 | 15.0 | 45 | 0.0 | 225.0 |
| 5 | 1.0 | 16.0 | 57 | 0.0 | 256.0 |
| 7 | 1.0 | 15.0 | 56 | 1.0 | 225.0 |
| 11 | 1.0 | 14.0 | 54 | 1.0 | 196.0 |
df3['exp'] = df3.edad-df3.esc
df3['exp2'] = df3.exp**2
df3['exp_sexo'] = df3.exp*df3.sexo2
y = np.log(df3.ytrabajocor)
X = df3[["esc", "exp", "exp2", "sexo2", "exp_sexo"]]
X = sm.add_constant(X)
X.head()
<ipython-input-18-79fecfcd28f3>:1: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df3['exp'] = df3.edad-df3.esc
<ipython-input-18-79fecfcd28f3>:2: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df3['exp2'] = df3.exp**2
<ipython-input-18-79fecfcd28f3>:3: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead
See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
df3['exp_sexo'] = df3.exp*df3.sexo2
| const | esc | exp | exp2 | sexo2 | exp_sexo | |
|---|---|---|---|---|---|---|
| 0 | 1.0 | 12.0 | 22.0 | 484.0 | 1.0 | 22.0 |
| 3 | 1.0 | 15.0 | 30.0 | 900.0 | 0.0 | 0.0 |
| 5 | 1.0 | 16.0 | 41.0 | 1681.0 | 0.0 | 0.0 |
| 7 | 1.0 | 15.0 | 41.0 | 1681.0 | 1.0 | 41.0 |
| 11 | 1.0 | 14.0 | 40.0 | 1600.0 | 1.0 | 40.0 |
model = sm.OLS(y, X)
results = model.fit()
print(results.summary())
OLS Regression Results
==============================================================================
Dep. Variable: ytrabajocor R-squared: 0.265
Model: OLS Adj. R-squared: 0.265
Method: Least Squares F-statistic: 5151.
Date: Tue, 26 Oct 2021 Prob (F-statistic): 0.00
Time: 11:08:12 Log-Likelihood: -1.1887e+05
No. Observations: 71466 AIC: 2.378e+05
Df Residuals: 71460 BIC: 2.378e+05
Df Model: 5
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 9.7314 0.030 326.486 0.000 9.673 9.790
esc 0.1522 0.002 100.943 0.000 0.149 0.155
exp 0.0820 0.001 71.234 0.000 0.080 0.084
exp2 -0.0011 1.56e-05 -68.238 0.000 -0.001 -0.001
sexo2 -0.1503 0.021 -7.152 0.000 -0.191 -0.109
exp_sexo -0.0136 0.001 -23.036 0.000 -0.015 -0.012
==============================================================================
Omnibus: 31679.342 Durbin-Watson: 1.650
Prob(Omnibus): 0.000 Jarque-Bera (JB): 197590.127
Skew: -2.052 Prob(JB): 0.00
Kurtosis: 10.037 Cond. No. 1.12e+04
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[2] The condition number is large, 1.12e+04. This might indicate that there are
strong multicollinearity or other numerical problems.
y = np.log(df3.ytrabajocor)
X = df3[["esc", "edad", "sexo2"]]
X = sm.add_constant(X)
X.head()
| const | esc | edad | sexo2 | |
|---|---|---|---|---|
| 0 | 1.0 | 12.0 | 34 | 1.0 |
| 3 | 1.0 | 15.0 | 45 | 0.0 |
| 5 | 1.0 | 16.0 | 57 | 0.0 |
| 7 | 1.0 | 15.0 | 56 | 1.0 |
| 11 | 1.0 | 14.0 | 54 | 1.0 |
model = sm.OLS(y, X)
results = model.fit()
print(results.summary())
OLS Regression Results
==============================================================================
Dep. Variable: ytrabajocor R-squared: 0.212
Model: OLS Adj. R-squared: 0.212
Method: Least Squares F-statistic: 6423.
Date: Mon, 26 Jul 2021 Prob (F-statistic): 0.00
Time: 23:38:58 Log-Likelihood: -1.2134e+05
No. Observations: 71466 AIC: 2.427e+05
Df Residuals: 71462 BIC: 2.427e+05
Df Model: 3
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 10.5982 0.028 380.688 0.000 10.544 10.653
esc 0.1696 0.001 124.958 0.000 0.167 0.172
edad 0.0039 0.000 10.597 0.000 0.003 0.005
sexo2 -0.5787 0.010 -58.179 0.000 -0.598 -0.559
==============================================================================
Omnibus: 32963.117 Durbin-Watson: 1.642
Prob(Omnibus): 0.000 Jarque-Bera (JB): 198868.520
Skew: -2.170 Prob(JB): 0.00
Kurtosis: 9.925 Cond. No. 269.
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
print('Parámetros: ', results.params)
print('Error estandar: ', results.bse)
print('Valores predichos: ', results.predict())
Parámetros: const 10.598153
esc 0.169602
edad 0.003898
sexo2 -0.578690
dtype: float64
Error estandar: const 0.027839
esc 0.001357
edad 0.000368
sexo2 0.009947
dtype: float64
Valores predichos: [12.18721169 13.31758263 13.5339568 ... 12.31583427 10.77744552
11.22416493]
Comparar resultados predichos
from statsmodels.sandbox.regression.predstd import wls_prediction_std
prstd, iv_l, iv_u = wls_prediction_std(results)
fig, ax = plt.subplots(figsize=(8,6))
ax.plot(X.esc, y, 'o', label="data")
[<matplotlib.lines.Line2D at 0x7f4486a0d9d0>]
Para ver ejemplos de gráficos en modelos de regresión pueden utilizar https://www.statsmodels.org/stable/examples/notebooks/generated/regression_plots.html
Por ejemplo, una visualización de las regresiones parciales se puede obtener mediante plot_partregress_grid. Esto muestra la relación entre la respuesta y la variable explicativa después de eliminar el efecto de todas las otras variables exógenas.
#Para ver gráficos de las regresiones parciales (regresionar la variable dependiente c/r a una variable condicional en el resto de las variables exógenas)
fig = sm.graphics.plot_partregress_grid(results)
fig.tight_layout(pad=1.0)
Para ver información de la regresión con respecto a una variable en específico podemos ocupar plot_regress_exog. Acá tenemos
Fitted plot
Residuo
Regresión parcial
Component-Component plus Residual (CCPR) plot: nos sirve para ver la relación entre uan variable independiente particular y la variable de respuesta, dado que otras variables indpendientes también están presentes en el modelo: \(Res+\hat{\beta}_iX_i\) versus \(X_i\)
fig = sm.graphics.plot_regress_exog(results, "esc")
fig.tight_layout(pad=1.0)
Ejemplo caso con menos ruido: ejemplo de juguete
x = np.linspace(0, 10, 100)
y = x + 0.5 * np.random.normal(size=len(x))
plt.plot(x,y)
[<matplotlib.lines.Line2D at 0x7f44946253d0>]
X = np.column_stack((x, x**2))
X = sm.add_constant(X)
res = sm.OLS(y, X).fit()
print(res.summary())
OLS Regression Results
==============================================================================
Dep. Variable: y R-squared: 0.974
Model: OLS Adj. R-squared: 0.973
Method: Least Squares F-statistic: 1807.
Date: Mon, 26 Jul 2021 Prob (F-statistic): 1.73e-77
Time: 23:31:42 Log-Likelihood: -66.869
No. Observations: 100 AIC: 139.7
Df Residuals: 97 BIC: 147.6
Df Model: 2
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const -0.0904 0.141 -0.641 0.523 -0.370 0.189
x1 1.0865 0.065 16.670 0.000 0.957 1.216
x2 -0.0098 0.006 -1.557 0.123 -0.022 0.003
==============================================================================
Omnibus: 0.781 Durbin-Watson: 2.028
Prob(Omnibus): 0.677 Jarque-Bera (JB): 0.817
Skew: -0.006 Prob(JB): 0.665
Kurtosis: 2.557 Cond. No. 144.
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
# y_hat = res.params[0] + results.params[1] * x + results.params[1] * x**2
res.params[2]
-0.009817635455210468
prstd, iv_l, iv_u = wls_prediction_std(res)
#Retorno:
#-standard error of prediction same length as rows of exog
#-lower und upper confidence bounds
fig, ax = plt.subplots(figsize=(8,6))
ax.plot(x, y, 'o', label="data")
ax.plot(x, res.fittedvalues, 'r--.', label="OLS")
ax.plot(x, iv_u, 'r--')
ax.plot(x, iv_l, 'r--')
ax.legend(loc='best');
fig, ax = plt.subplots(figsize=(8,6))
y_hat = res.params[0] + res.params[1] * x + res.params[2] * x**2
ax.plot(x, y, 'o', label="data")
ax.plot(x, res.fittedvalues, 'r--.', label="OLS")
ax.plot(x, y_hat, 'g', label="OLS")
[<matplotlib.lines.Line2D at 0x7f4494171280>]
Modelo Autorregresivo (AR)¶
Podemos estimar un modelo del tipo \(Y_t = \beta_0 + \beta_1 Y_{t-1} + \mu_t\)
En python podemos utilizar AutoReg: https://www.statsmodels.org/stable/examples/notebooks/generated/autoregressions.html
df = pd.read_excel("/home/felix/Dropbox/Computational_Economics/Intro_python/Data_OLS_AR/pib.xlsx")
df.dtypes
df.head()
| Periodo | PIB | |
|---|---|---|
| 0 | 1986-01-01 | 7899.666547 |
| 1 | 1986-04-01 | 8220.056395 |
| 2 | 1986-07-01 | 8355.276664 |
| 3 | 1986-10-01 | 8555.927503 |
| 4 | 1987-01-01 | 8626.993492 |
plt.plot(df.Periodo, df.PIB);
from pandas.plotting import lag_plot
lag_plot(df.PIB)
<AxesSubplot:xlabel='y(t)', ylabel='y(t + 1)'>
from statsmodels.tsa.ar_model import AutoReg, ar_select_order
from statsmodels.tsa.api import acf, pacf, graphics
mod = AutoReg(df.PIB, 1, old_names=False)
res = mod.fit()
print(res.summary())
AutoReg Model Results
==============================================================================
Dep. Variable: PIB No. Observations: 141
Model: AutoReg(1) Log Likelihood -1085.062
Method: Conditional MLE S.D. of innovations 562.000
Date: Tue, 27 Jul 2021 AIC 12.706
Time: 08:19:50 BIC 12.769
Sample: 1 HQIC 12.731
141
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
const 257.5324 123.602 2.084 0.037 15.278 499.787
PIB.L1 0.9985 0.005 203.603 0.000 0.989 1.008
Roots
=============================================================================
Real Imaginary Modulus Frequency
-----------------------------------------------------------------------------
AR.1 1.0015 +0.0000j 1.0015 0.0000
-----------------------------------------------------------------------------
Podemos actualizar el modelo a \(Y_t = \beta_0 + \beta_1 Y_{t-1} + \beta_2 Y_{t-2} + \beta_3 Y_{t-3} + \beta_4 Y_{t-4} + \beta_5 Y_{t-5} + \mu_t\)
mod = AutoReg(df.PIB, 5, old_names=False)
res = mod.fit()
print(res.summary())
AutoReg Model Results
==============================================================================
Dep. Variable: PIB No. Observations: 141
Model: AutoReg(5) Log Likelihood -1047.475
Method: Conditional MLE S.D. of innovations 535.438
Date: Tue, 27 Jul 2021 AIC 12.669
Time: 08:21:12 BIC 12.819
Sample: 5 HQIC 12.730
141
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
const 423.0718 133.111 3.178 0.001 162.179 683.965
PIB.L1 0.8942 0.083 10.802 0.000 0.732 1.056
PIB.L2 0.2591 0.123 2.105 0.035 0.018 0.500
PIB.L3 -0.3180 0.120 -2.658 0.008 -0.553 -0.083
PIB.L4 -0.5179 0.223 -2.323 0.020 -0.955 -0.081
PIB.L5 0.6816 0.195 3.488 0.000 0.299 1.065
Roots
=============================================================================
Real Imaginary Modulus Frequency
-----------------------------------------------------------------------------
AR.1 -0.8762 -0.6971j 1.1197 -0.3930
AR.2 -0.8762 +0.6971j 1.1197 0.3930
AR.3 0.7558 -0.7735j 1.0814 -0.1268
AR.4 0.7558 +0.7735j 1.0814 0.1268
AR.5 1.0006 -0.0000j 1.0006 -0.0000
-----------------------------------------------------------------------------
Para un resumen de la visualización de los residuos estandarizados podemos ocupar plot_diagnostics
fig = plt.figure(figsize=(16,9))
fig = res.plot_diagnostics(fig=fig, lags=30)
#Standarized residual:
#-residuo: Valor observado - valor predicho
#-standarized residual: residuo normalizado por el error estandar del modelo (RSE)
#Histogram plus: estima la distribución de los residuos estandarizados. Nos muestra la distribución normal (línea verde) como punto de comparación.
#Normal Q-Q : muestra si el residuo está distribuido normalmente. Lo que se espera es que los puntos se encuentren sobre la línea roja o cercanos a ella.
#Correlograma: nos muestra un gráfico de autocorrelaciones
Autocorrelaciones: https://www.statsmodels.org/stable/generated/statsmodels.graphics.tsaplots.plot_acf.html
sm.graphics.tsa.plot_acf(df.PIB, lags=40)
plt.show()
Actividad¶
Estime la ecuación de mincer: \(Ingreso_i = \beta_0 + \beta_1 esc_i + \beta_2 exp_i + \beta_3 exp_i^2 + \beta_4 sexo_i + \mu_i\) donde :
ingreso: log(ingreso del trabajo)
esc: escolaridad
exp: experiencia = edad - escolaridad
exp2: expediencia al cuadrado
sexo: variable dicotómica si es hombre (0) o mujer (1).
Estime un modelo AR del tipo \(\Delta y_t = \Delta y_{t-1}\) donde:
\(y_t\) es el PIB trimestral en el periodo t.
\(\Delta y_t\) es la variación del PIB trimestral en el periodo t.
\(\Delta y_{t-1}\) es la variación del PIB trimestral en el periodo t-1.











